264

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

你确定吗?[是/否]

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

原因是hg pushandhg out听起来很相似,有时当我想要时hgoutrepo,我可能会不小心输入hgpushrepo(两者都是别名)。

更新:如果它可以是带有另一个命令的内置命令,例如:confirm && hg push ssh://...那就太好了......只是一个可以要求 a yesorno并继续其余 if的命令yes

4

19 回答 19

394

这些是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://..
于 2010-07-12T20:36:50.580 回答
24

这里大致是你想要的一个片段。让我找出如何转发论点。

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:)

于 2010-07-12T20:04:12.617 回答
17

回车很容易绕过确认,我发现不断提示有效输入很有用。

这是一个使这变得容易的函数。如果没有收到 Y|N,“invalid input”会显示为红色,并再次提示用户。

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

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

于 2015-09-22T04:00:25.550 回答
14

为避免显式检查 'yes' 的这些变体,您可以将 bash 正则表达式运算符 '=~' 与正则表达式一起使用:

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

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

于 2010-07-12T20:33:23.387 回答
8

这可能是一个黑客:

如问题在Unix / Bash中,“xargs -p”是在运行任何命令之前提示确认的好方法吗?

我们可以xargs用来做这项工作:

echo ssh://username@www.example.com//somepath/morepath | xargs -p hg push

当然,这将被设置为别名,例如 hgpushrepo

例子:

$ echo foo | xargs -p ls -l
ls -l foo?...y
-rw-r--r--  1 mikelee    staff  0 Nov 23 10:38 foo

$ echo foo | xargs -p ls -l
ls -l foo?...n

$
于 2010-08-03T21:15:57.720 回答
6

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

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只读取一个字符。无需按Enter。如果不是“n”或“N”,则假定为“Y”。只需按 enter 也意味着 Y。

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

于 2018-04-11T14:14:23.273 回答
4

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


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
}
于 2010-07-12T22:16:02.717 回答
4
read -r -p "Are you sure? [Y/n]" response
  response=${response,,} # tolower
  if [[ $response =~ ^(yes|y| ) ]] || [[ -z $response ]]; then
      your-action-here
  fi
于 2010-07-14T13:17:48.500 回答
3

好吧,这是我的版本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. my Git on Windowsonly hasbash-3.1和 has no trueor false,所以return改用。当然,这也兼容 bash-4.4(Git for Windows 中的当前版本)。
  5. 使用 IPython 风格的 "(y/[n])" 清楚地表明 "n" 是默认值。
于 2016-09-13T05:53:09.133 回答
3

无需按回车

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

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

按回车时默认为“否”

请注意,N是大写的。这里输入被按下,接受默认值:

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

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

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

$ 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- 要求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
}
于 2018-06-28T06:26:42.237 回答
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您会看到它仍然设置,直到您打开或关闭终端或再次设置它。

于 2019-09-26T17:12:54.413 回答
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但可能在您的外壳中失败
  • 如果参数干扰echoxargs
  • 无数其他错误,因为 shell 脚本很难
于 2013-02-02T01:52:40.977 回答
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"
于 2014-01-11T11:54:51.317 回答
0

这并不完全是“要求是或否”,而只是一种技巧:别名为hg push ...not tohgpushrepo而是 to hgpushrepoconfirmedpush,当我可以拼出整个事情时,左脑已经做出了合乎逻辑的选择。

于 2010-07-13T01:10:42.483 回答
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 读取的第一个字符。

于 2015-12-02T06:04:52.600 回答
0

下面的代码结合了两件事

  1. shopt -s nocasematch 将处理不区分大小写的问题

  2. 如果条件将接受这两个输入,则您传递是,是,是,y。

    shopt -s nocasematch

    如果 [[ sed-4.2.2.$LINE =~ (yes|y)$ ]]

    然后退出 0

于 2017-09-30T14:21:43.170 回答
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]? : "
于 2017-11-09T09:20:14.343 回答
0

我知道这是一个老问题,但这可能对某人有帮助,这里没有解决。

有人问我如何在从文件接收输入的脚本中使用 rm -i。由于脚本的文件输入通常是从 STDIN 接收的,我们需要对其进行更改,以便仅从 STDIN 接收对 rm 命令的响应。这是解决方案:

#!/bin/bash
while read -u 3 line
do
 echo -n "Remove file $line?"
 read -u 1 -n 1 key
 [[ $key = "y" ]] &&  rm "$line"
 echo
done 3<filelist

如果按下“y”键(仅限小写)以外的任何键,则不会删除文件。没有必要在键后按回车键(因此使用 echo 命令将新行发送到显示器)。请注意,POSIX bash“读取”命令不支持 -u 开关,因此需要寻求解决方法。

于 2020-12-01T20:02:08.897 回答
0

我试图使用 bash 命令安装 ant,但得到了

Error: Process completed with exit code 1.

下面的命令对我有用

sudo yes | apt install ant
于 2021-12-29T12:43:21.387 回答