如何在Bash脚本中提示用户确认?

830

我想在可能存在风险的bash脚本顶部添加一个快速的“您确定吗?”提示以便确认,最简单/最好的方法是什么?


Related - Dennis Williamson
10个回答

1385
read -p "Are you sure? " -n 1 -r
echo    # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
    # do dangerous stuff
fi

我采纳了 levislevis85 的建议(谢谢!),并在 read 中添加了 -n 选项,以接受一个字符而无需按下 Enter 键。您可以使用其中一个或两个选项。

此外,否定形式可能如下所示:

read -p "Are you sure? " -n 1 -r
echo    # (optional) move to a new line
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
    [[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 # handle exits from shell or function but don't exit interactive shell
fi

然而,正如Erich所指出的,在某些情况下,例如由于在错误的shell中运行脚本而导致的语法错误,否定形式可能会允许脚本继续执行“危险的内容”。故障模式应优先考虑最安全的结果,因此只应使用第一个非否定的if
解释: read命令输出提示(-p "prompt"),然后接受一个字符(-n 1)并按原样接受反斜杠(-r)(否则read将把反斜杠视为转义符并等待第二个字符)。如果您没有提供名称(例如read -p "my prompt" -n 1 -r my_var),则默认变量用于存储read的结果是$REPLYif语句使用正则表达式来检查$REPLY中的字符是否匹配(=~)大写或小写的“Y”。这里使用的正则表达式表示“以括号表达式([Yy])中的字符列表之一开头(^)且完全由该字符组成($)的字符串”。锚点(^$)防止匹配更长的字符串。在这种情况下,它们有助于加强read命令中设置的一个字符限制。
否定形式使用逻辑“非”运算符(!)来匹配(=~)任何不是“Y”或“y”的字符。另一种表达方式不太可读,而且在我看来并没有清楚地表达出意图。然而,这是它的样子:if [[ $REPLY =~ ^[^Yy]$ ]]

28
在“读取”之后,应该执行“回显”以使光标返回到下一行。(只需使用没有参数的原始“echo”即可完成操作) - AlexChaffee
22
如果没有提供变量名,$REPLY会自动设置。 - Dennis Williamson
9
只是一个有关否定形式的警告——如果您的用户在旧版 Bourne sh shell 中运行它,那么存在读取和条件测试 [[ 失败但脚本仍将继续执行而不退出的风险——这可能不是您想要的,因此正面版本更安全。 - ErichBSchulz
3
这个命令是什么意思:[[ $REPLY =~ ^[Yy]$ ]] || exit -1? 如果在旧版本的shell中运行,它会如何评估? - Scolytus
7
只是想指出 - 在测试时忘记在顶部添加哈希标记会导致错误。请确保在脚本顶部添加 #!/usr/bin/env bash(或类似的有效哈希标记)。 - nealio82
显示剩余46条评论

246

用例/结束用例。

read -p "Continue (y/n)?" choice
case "$choice" in 
  y|Y ) echo "yes";;
  n|N ) echo "no";;
  * ) echo "invalid";;
esac

优点:

  1. 更整洁
  2. 更容易使用“OR”条件
  3. 可以使用字符范围,例如[yY][eE][sS]接受单词“yes”,其中任何一个字符都可以是小写或大写。

10
好的解决方案。个人而言,如果bash脚本可能会导致影响很大,我希望让用户手动输入“yes”。 - SiegeX
当输入为 no 时,您可以使用 echo "Quitting script."; exit;; 来退出脚本。但是,如果输入为 yes,则脚本将继续执行 esac 后面的内容。 - Alaa Ali
1
如果你写 n|N ) echo "no"; return;;,那么如果你输入 'n',脚本将在此结束,否则将继续执行,这是你的意思吗? - Rellikiox
2
@SiegeX 如果这真的非常严重,你可以让用户打出“快速的棕色狐狸跳过懒狗” :P - brettwhiteman
4
当用户输入无效时,如何要求用户重新输入。如果连续三次输入无效,则执行“return;”。 - Bin

70

尝试使用read shell内置命令:

read -p "Continue (y/n)?" CONT
if [ "$CONT" = "y" ]; then
  echo "yaaa";
else
  echo "booo";
fi

58

这样你会得到“是”、“yes”或者“Enter”

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

如果您正在使用 zsh,请尝试以下操作:

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

不接受默认的 Y。 - Gelldur
1
对于默认值Y如果[[ $response =~ ^(yes|y| ) ]] | [ -z $response ]; then - Gelldur
2
在正则表达式中,无需匹配yes和y,只需要匹配y开头即可。此外,如果默认值为no,则以下内容将会有所帮助。read "response?Are you sure ? [Y/n] " && if [[ "$response" =~ ^[Yy] ]]; then echo "Yes, you did it."; else echo "No, narrow escape"; fi - Gopal

32
这是我使用的函数:
function ask_yes_or_no() {
    read -p "$1 ([y]es or [N]o): "
    case $(echo $REPLY | tr '[A-Z]' '[a-z]') in
        y|yes) echo "yes" ;;
        *)     echo "no" ;;
    esac
}

并且一个使用它的例子:

if [[ "no" == $(ask_yes_or_no "Are you sure?") || \
      "no" == $(ask_yes_or_no "Are you *really* sure?") ]]
then
    echo "Skipped."
    exit 0
fi

# Do something really dangerous...
  • 输出始终是 "yes" 或 "no"
  • 默认为 "no"
  • 除了 "y" 或 "yes" 以外的任何输入都返回 "no",所以对于危险的 bash 脚本来说非常安全
  • 并且不区分大小写,"Y"、"Yes" 或 "YES" 都等同于 "yes"

24

这是我在其他地方找到的,有更好的版本可能吗?

read -p "Are you sure you wish to continue?"
if [ "$REPLY" != "yes" ]; then
   exit
fi

9
[[ -f ./${sname} ]] && read -p "File exists. Are you sure? " -n 1

[[ ! $REPLY =~ ^[Yy]$ ]] && exit 1

我在一个函数中使用了这个功能来查找现有的文件并在覆盖之前提示。


8
echo are you sure?
read x
if [ "$x" = "yes" ]
then
  # do the dangerous stuff
fi

4
#!/bin/bash
echo Please, enter your name
read NAME
echo "Hi $NAME!"
if [ "x$NAME" = "xyes" ] ; then
 # do something
fi

这是一个简短的bash脚本,用于读取并回显结果。

3

qnd:使用

read VARNAME
echo $VARNAME

如果需要一行响应而没有 readline 支持, 那么可以使用以下命令。之后,您可以按照自己的方式测试 $VARNAME。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接