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

Are you sure? [Y/n]

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

原因是hgpush和hgout听起来很相似,有时当我想要hgoutrepo时,我可能会意外地键入hgpushrepo(两者都是别名)。

更新:如果可以像内置命令一样使用另一个命令,比如:confirm && hg push ssh://…那太好了……只是一个命令,可以询问“是”或“否”,如果是则继续其余的操作。


当前回答

我知道这是一个老问题,但这可能会帮助到一些人,它还没有在这里解决。

有人问我如何在接收文件输入的脚本中使用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“read”命令不支持-u开关,因此需要寻找解决方案。

其他回答

在游戏后期,我创建了前面答案的确认函数的另一个变体:

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脚本很难,所以有无数的其他bug

不一样,但不管怎样都行得通。

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

输出: 一遍吗?Y / n n 一遍吗?Y / n任何 一遍吗?Y / n 7 一遍吗?Y / n & 一遍吗?Y / n nsijf $

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

不需要按enter

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

返回0=yes和1=no 不需要按enter键-只需一个字符 可以按enter键接受默认选择吗 可以禁用默认选择来强制选择吗 适用于zsh和bash。

按enter键时默认为“no”

注意,N是大写的。此处按下enter键,接受默认值:

$ 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 *

按enter键时默认为“yes”

注意,Y是大写的:

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

上面,我只是按了回车键,命令就运行了。

输入- require y或n时无默认值

$ 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]没有大写?

Code

# 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
}

这些是哈米什的回答中更紧凑、更通用的形式。它们可以处理任何大小写字母的混合:

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

或者,对于Bash >= version 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() {
    # 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://..

or

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

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

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”。按回车键也意味着Y。

(至于真正的问题:使它成为一个bash脚本,并更改您的别名指向该脚本,而不是之前所指向的内容)