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

时间:2010-07-12 19:58:33

标签: bash alias confirmation

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

Are you sure? [Y/n]

表示Mercurial的hg push ssh://username@www.example.com//somepath/morepath,它实际上是别名。是否有可以添加到别名的标准命令来实现它?

原因是hg pushhg out听起来很相似,有时当我需要hgoutrepo时,我可能会偶然输入hgpushrepo(两者都是别名)。

更新:如果它可以像内置命令一样使用另一个命令,例如:confirm && hg push ssh://...那个很棒......只是一个可以要求的命令yesno,如果yes,请继续使用其余内容。

18 个答案:

答案 0 :(得分:289)

这些是Hamish's answer更紧凑和多功能的形式。他们处理大写和小写字母的任何混合:

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://..

答案 1 :(得分: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:)

答案 2 :(得分:11)

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

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

测试用户输入是以'y'还是'Y'开头,后跟零或更多'es'。

答案 3 :(得分:10)

使用回车可以轻松绕过确认,我发现连续提示有效输入很有用。

这是一个简单易用的功能。如果未收到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

您可以通过传递参数

来更改默认提示

答案 4 :(得分:4)

这可能是一个黑客:

如问题In Unix / Bash, is "xargs -p" a good way to prompt for confirmation before running any command?

我们可以使用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

$

答案 5 :(得分:3)

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

答案 6 :(得分:3)

将以下内容添加到/ 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
}

答案 7 :(得分:2)

嗯,这是我的confirm版本,修改自詹姆斯的一个:

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且没有truefalse,因此请改用return。当然,这也与bash-4.4(Git for Windows中的当前版本)兼容。
  5. 使用IPython-style“(y / [n])”清楚地表明“n”是默认值。

答案 8 :(得分: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,您会看到它仍然处于设置状态,直到您打开或关闭终端或再次设置它为止。

答案 9 :(得分: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可能会失败
  • 如果参数干扰echoxargs
  • 可能会失败
  • 因为shell脚本很难而存在大量其他错误

答案 10 :(得分: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"

答案 11 :(得分:1)

无需按Enter键

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

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

按Enter键时默认为“否”

请注意,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 *

按Enter键时默认为“是”

请注意,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
}

答案 12 :(得分:0)

这不完全是“要求是或否”,而只是一个黑客攻击:将hg push ...别名改为hgpushrepo而不是hgpushrepoconfirmedpush,并且当我拼出时整个事情,左脑已经做出了合理的选择。

答案 13 :(得分: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  

输出:
     再次?是/否N
     再次?是/否任何事      再次?是/否7
     再次? Y / n&amp;
     再次?是/否nsijf
$

现在只检查$ i读取的第一个字符。

答案 14 :(得分:0)

下面的代码是结合两件事

  1. shopt -s nocasematch将照顾不区分大小写的

  2. 如果条件同时接受输入,则传递yes,Yes,YES,y。

    shopt -s nocasematch

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

    然后退出0

    网络连接

答案 15 :(得分:0)

这是我使用本地化正则表达式的解决方案。所以在德语中,“j”的“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]? : "

答案 16 :(得分:0)

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

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

read -n 1只读一个字符。如果它不是小写的&#39; n,则假定它是&#39; Y&#39;。

(至于真正的问题:制作一个bash脚本并将你的别名改为指向那个脚本而不是之前指向的那个)

答案 17 :(得分: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开关,因此需要寻求解决方法。