在Bash中,如何在任何命令或别名中添加“您确定[Y / n]”?


228

在这种情况下,我想在Bash中添加一个确认

你确定吗?[是/否]

对于Mercurial来说hg push ssh://username@www.example.com//somepath/morepath,实际上是一个别名。是否可以将标准命令添加到别名中来实现它?

原因是hg pushhg out听起来相似,有时在我需要时hgoutrepo,我可能会不小心键入hgpushrepo(均为别名)。

更新:如果它可以像是内置命令和另一个命令一样,例如:confirm && hg push ssh://...那就太好了……只是一个可以要求yesor 的命令,no其余的if 可以继续yes


1
您可能要使用函数而不是别名。来自info bash:“几乎所有目的,shell函数都比别名更受青睐。”
暂停,直到另行通知。

真?即使对于像ls -lrm -i
极性

5
对于几乎每一个,不是每一个。顺便说一句,从来没有这样做alias rm='rm -i'。有一天,最需要的时候,别名就不会出现boom!了,重要的事情将会丢失。
暂停,直到另行通知。

等待,如果您没有的别名rm -i,那么您也不能指望拥有shell脚本。那么,您总是rm -i每次都键入吗?
极性

8
这与习惯有关。您可以在我之前的评论中创建一个别名,并习惯于键入rm并期待其-i行为,然后有一天该别名不存在(由于某种原因,它未设置或未设置,或者您使用的是其他系统),然后键入rm,然后会立即删除未经确认的内容。糟糕!但是,如果您使用了类似的别名,alias askrm='rm -i'那么就可以了,因为会出现“找不到命令”错误。
暂停,直到另行通知。

Answers:


332

这些是Hamish答案的更紧凑和通用的形式。它们处理大小写字母的任何混合形式:

read -r -p "Are you sure? [y/N] " response
case "$response" in
    [yY][eE][sS]|[yY]) 
        do_something
        ;;
    *)
        do_something_else
        ;;
esac

或者,对于Bash> =版本3.2:

read -r -p "Are you sure? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]
then
    do_something
else
    do_something_else
fi

注意:如果$response为空字符串,则会出现错误。要解决此问题,只需添加引号:"$response"。–始终在包含字符串的变量中使用双引号(例如:更喜欢使用"$@"代替$@)。

或者,Bash 4.x:

read -r -p "Are you sure? [y/N] " response
response=${response,,}    # tolower
if [[ "$response" =~ ^(yes|y)$ ]]
...

编辑:

为了响应您的编辑,以下是confirm根据答案中的第一个版本创建和使用命令的方式(与其他两个版本相似):

confirm() {
    # call with a prompt string or use a default
    read -r -p "${1:-Are you sure? [y/N]} " response
    case "$response" in
        [yY][eE][sS]|[yY]) 
            true
            ;;
        *)
            false
            ;;
    esac
}

要使用此功能:

confirm && hg push ssh://..

要么

confirm "Would you really like to do a push?" && hg push ssh://..

9
实际上,对于当前测试,它应该为[y / N],而不是[Y / n]。
西蒙·欧格斯特

值得一提的是,如果要检查not equal to第二个示例,则应强制转换$response变量。例如:if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]]
若昂·库尼亚

@JoãoCunha:这是“不匹配”而不是“不等于”,因为=~它是正则表达式匹配运算符。
暂停,直到另行通知。

@DennisWilliamson正确,这就是我想要表达的意思。由于某些原因无法编辑我的评论。
若昂·库尼亚

6
不错的通用功能,是/否。支持强提示,并且可以选择将“ y”或“ n”设置为默认值。
wkw 2015年

19

这是您想要的大致片段。让我找出如何转发这些论点。

read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt == "y" || $prompt == "Y" || $prompt == "yes" || $prompt == "Yes" ]]
then
  # http://stackoverflow.com/questions/1537673/how-do-i-forward-parameters-to-other-command-in-bash-script
else
  exit 0
fi

提防yes | command name here:)


13

回车很容易绕过确认,我发现连续提示输入有效信息很有用。

这是一个简化此功能的函数。如果未收到Y | N,则“无效输入”以红色显示,并再次提示用户。

prompt_confirm() {
  while true; do
    read -r -n 1 -p "${1:-Continue?} [y/n]: " REPLY
    case $REPLY in
      [yY]) echo ; return 0 ;;
      [nN]) echo ; return 1 ;;
      *) printf " \033[31m %s \n\033[0m" "invalid input"
    esac 
  done  
}

# example usage
prompt_confirm "Overwrite File?" || exit 0

您可以通过传递参数来更改默认提示


12

为了避免显式检查“ yes”的这些变体,您可以将bash正则表达式运算符'=〜'与正则表达式配合使用:

read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt =~ [yY](es)* ]]
then
(etc...)

这将测试用户输入是以“ y”还是“ y”开头,然后是零个或多个“ es”。



4

将以下内容添加到您的/ etc / bashrc文件中。该脚本添加了一个常驻的“函数”,而不是一个别名为“确认”的别名。


function confirm( )
{
#alert the user what they are about to do.
echo "About to $@....";
#confirm with the user
read -r -p "Are you sure? [Y/n]" response
case "$response" in
    [yY][eE][sS]|[yY]) 
              #if yes, then execute the passed parameters
               "$@"
               ;;
    *)
              #Otherwise exit...
              echo "ciao..."
              exit
              ;;
esac
}

真好 但是,需要进行一些小的更正:您应该在双引号周围加注,$response$@避免出现误分叉,其中包含一些多余的分号,并且*条件应返回而不是退出。
戈登·戴维森

需要明确的是,某些语句结尾的单分号是不必要的。
暂停,直到另行通知。

4

这可能有点太短了,但是对于我自己的私人使用来说,它的效果很好

read -n 1 -p "Push master upstream? [Y/n] " reply; 
if [ "$reply" != "" ]; then echo; fi
if [ "$reply" = "${reply#[Nn]}" ]; then
    git push upstream master
fi

read -n 1只读取一个字符。无需按回车键。如果不是“ n”或“ N”,则假定为“ Y”。只需按Enter也表示Y。

(至于真正的问题:制作一个bash脚本,并更改​​别名以指向该脚本,而不是之前指向的内容)


简短而甜美,正是我所需要的。谢谢!
Raymo111 '19

3
read -r -p "Are you sure? [Y/n]" response
  response=${response,,} # tolower
  if [[ $response =~ ^(yes|y| ) ]] || [[ -z $response ]]; then
      your-action-here
  fi

因此,空格字符表示可以吗?
Xen2050

除“是”或“是”之外的所有内容都会确认操作,因此您是对的!@ xen2050
SergioAraujo

3

无需按Enter

这是一个更长的但可重用的模块化方法:

  • 返回0= y和1= no
  • 无需按下Enter键-只需一个字符
  • 可以按enter接受默认选择
  • 可以禁用默认选择以强制选择
  • 适用于zshbash

按下回车键时默认为“否”

请注意,N大写。在这里按下回车键,接受默认值:

$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?

另请注意, [y/N]?是自动附加的。默认值为“ no”,因此不会回显任何内容。

重新提示,直到给出有效的响应:

$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *

按下回车键时默认为“是”

请注意,将Y大写:

$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *

在上面,我只是按下Enter键,所以命令运行了。

无默认开启enter-要求yn

$ get_yes_keypress "Here you cannot press enter. Do you like this"
Here you cannot press enter. Do you like this [y/n]? k
Here you cannot press enter. Do you like this [y/n]?
Here you cannot press enter. Do you like this [y/n]? n
$ echo $?
1

在这里,1否则返回false。注意在没有大写[y/n]?

# Read a single char from /dev/tty, prompting with "$*"
# Note: pressing enter will return a null string. Perhaps a version terminated with X and then remove it in caller?
# See https://unix.stackexchange.com/a/367880/143394 for dealing with multi-byte, etc.
function get_keypress {
  local REPLY IFS=
  >/dev/tty printf '%s' "$*"
  [[ $ZSH_VERSION ]] && read -rk1  # Use -u0 to read from STDIN
  # See https://unix.stackexchange.com/q/383197/143394 regarding '\n' -> ''
  [[ $BASH_VERSION ]] && </dev/tty read -rn1
  printf '%s' "$REPLY"
}

# Get a y/n from the user, return yes=0, no=1 enter=$2
# Prompt using $1.
# If set, return $2 on pressing enter, useful for cancel or defualting
function get_yes_keypress {
  local prompt="${1:-Are you sure} [y/n]? "
  local enter_return=$2
  local REPLY
  # [[ ! $prompt ]] && prompt="[y/n]? "
  while REPLY=$(get_keypress "$prompt"); do
    [[ $REPLY ]] && printf '\n' # $REPLY blank if user presses enter
    case "$REPLY" in
      Y|y)  return 0;;
      N|n)  return 1;;
      '')   [[ $enter_return ]] && return "$enter_return"
    esac
  done
}
    
# Credit: http://unix.stackexchange.com/a/14444/143394
# Prompt to confirm, defaulting to NO on <enter>
# Usage: confirm "Dangerous. Are you sure?" && rm *
function confirm {
  local prompt="${*:-Are you sure} [y/N]? "
  get_yes_keypress "$prompt" 1
}    

# Prompt to confirm, defaulting to YES on <enter>
function confirm_yes {
  local prompt="${*:-Are you sure} [Y/n]? "
  get_yes_keypress "$prompt" 0
}

2

好吧,这是我的版本confirm,是从James的版本修改而来的:

function confirm() {
  local response msg="${1:-Are you sure} (y/[n])? "; shift
  read -r $* -p "$msg" response || echo
  case "$response" in
  [yY][eE][sS]|[yY]) return 0 ;;
  *) return 1 ;;
  esac
}

这些更改是:

  1. 用于local防止变量名冲突
  2. read用于$2 $3 ...控制其动​​作,因此您可以使用-n-t
  3. 如果read退出失败,echo换行以获取美感
  4. Git on Windows唯一的有bash-3.1,没有true或没有false,所以return改用。当然,这也与bash-4.4(Windows版Git中的最新版本)兼容。
  5. 请使用IPython风格的“(y / [n])”清楚地表明“ n”是默认值。

2

此版本允许您使用多个案例yYnN

  1. 可选:重复问题,直到提供批准的问题

  2. 可选:忽略任何其他答案

  3. 可选:如果需要,退出终端

    confirm() {
        echo -n "Continue? y or n? "
        read REPLY
        case $REPLY in
        [Yy]) echo 'yup y' ;; # you can change what you do here for instance
        [Nn]) break ;;        # exit case statement gracefully
        # Here are a few optional options to choose between
        # Any other answer:
    
        # 1. Repeat the question
        *) confirm ;;
    
        # 2. ignore
        # *) ;;
    
        # 3. Exit terminal
        # *) exit ;;
    
        esac
        # REPLY=''
    }

还要注意这一点:在此函数的最后一行,清除REPLY变量。否则,如果您echo $REPLY将看到它仍处于设置状态,直到您打开或关闭终端或再次设置它。


1

游戏晚了,但是我创建confirm了先前答案的另一种功能:

confirm ()
{
    read -r -p "$(echo $@) ? [y/N] " YESNO

    if [ "$YESNO" != "y" ]; then
        echo >&2 "Aborting"
        exit 1
    fi

    CMD="$1"
    shift

    while [ -n "$1" ]; do
        echo -en "$1\0"
        shift
    done | xargs -0 "$CMD" || exit $?
}

要使用它:

confirm your_command

特征:

  • 在提示符下打印命令
  • 使用NULL分隔符传递参数
  • 保留命令的退出状态

错误:

  • echo -en可以使用,bash但可能在您的shell中失败
  • 如果参数干扰echo或可能会失败xargs
  • 大量的其他错误,因为shell脚本很难

1

尝试,

 #!/bin/bash
 pause ()
 {
 REPLY=Y
 while [ "$REPLY" == "Y" ] || [ "$REPLY" != "y" ]
 do
  echo -e "\t\tPress 'y' to continue\t\t\tPress 'n' to quit"
  read -n1 -s
      case "$REPLY" in
      "n")  exit                      ;;
      "N")  echo "case sensitive!!"   ;; 
      "y")  clear                     ;;
      "Y")  echo "case sensitive!!"   ;;
      * )  echo "$REPLY is Invalid Option"     ;;
 esac
 done
 }
 pause
 echo "Hi"

0

这不完全是“要求是或否”,而只是一个小技巧:在我可以拼出全部内容时,将别名“ hg push ...not”改为“ hgpushrepoto to” hgpushrepoconfirmedpush,而左脑则做出了合理的选择。


1
但是您知道您将使用该TAB密钥!
Hamish Grubijan

好的,是的,但至少我会看一眼命令,发现它很奇怪,在按下Enter键之前要三思而后行
nonopolarity

0

不一样,但是想法仍然有效。

#!/bin/bash  
i='y'  
while [ ${i:0:1} != n ]  
do  
    # Command(s)  
    read -p " Again? Y/n " i  
    [[ ${#i} -eq 0 ]] && i='y'  
done  

输出:
再次?是/否
否?是/否
再次发生吗?是/还是7
?是/
否?是nsijf
$

现在仅检查$ i的第一个字符。


0

下面的代码结合了两件事

  1. shopt -s nocasematch,将区分大小写

  2. 并且如果条件将接受两个输入,则您传递yes,Yes,YES,y。

    shopt -s nocasematch

    如果[[sed-4.2.2。$ LINE =〜(yes | y)$]]

    然后退出0

    科幻


0

这是我使用本地化的正则表达式的解决方案。因此,在德语中,“ Ja”的“ j”也将被解释为是。

第一个参数是问题,如果第二个参数是“ y”,则默认答案为“是”,否则为默认答案。如果答案为“是”,则返回值为0;如果答案为“否”,则返回值为1。

function shure(){
    if [ $# -gt 1 ] && [[ "$2" =~ ^[yY]*$ ]] ; then
        arg="[Y/n]"
        reg=$(locale noexpr)
        default=(0 1)
    else
        arg="[y/N]"
        reg=$(locale yesexpr)
        default=(1 0)
    fi
    read -p "$1 ${arg}? : " answer
    [[ "$answer" =~ $reg ]] && return ${default[1]} || return ${default[0]}
}

这是基本用法

# basic example default is no
shure "question message" && echo "answer yes" || echo "answer no"
# print "question message [y/N]? : "

# basic example default set to yes
shure "question message" y && echo "answer yes" || echo "answer no"
# print "question message [Y/n]? : "
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.