如何在Linux shell脚本中提示用户输入Yes/No/Cancel?

1861
我想暂停shell脚本中的输入,并提示用户进行选择,例如标准的“是”、“否”或“取消”类型的问题。在典型的bash提示符下,如何实现这一点?

40
请注意:提示符的惯例是如果您提供了 [yn] 选项,则大写字母是默认值。即[Yn] 默认为“yes”,[yN] 默认为“no”。请参见https://ux.stackexchange.com/a/40445/43532 - Tyzoid
4
如果有从ZSH过来的人,请参考这个答案以了解如何使用read命令进行提示。 - smac89
2
你也可以考虑查看我在 U&L.SE 上的相关问答,了解在 bash 中暂停的规范方式。提供的结果可以轻松转移。 - Cadoiz
39个回答

7
我注意到没有人发布一个显示多行 echo 菜单的答案,以满足这种简单用户输入,所以这是我的尝试:
#!/bin/bash

function ask_user() {    

echo -e "
#~~~~~~~~~~~~#
| 1.) Yes    |
| 2.) No     |
| 3.) Quit   |
#~~~~~~~~~~~~#\n"

read -e -p "Select 1: " choice

if [ "$choice" == "1" ]; then

    do_something

elif [ "$choice" == "2" ]; then

    do_something_else

elif [ "$choice" == "3" ]; then

    clear && exit 0

else

    echo "Please select 1, 2, or 3." && sleep 3
    clear && ask_user

fi
}

ask_user

这个方法的发布是希望有人能够发现它的实用性和节省时间的特点。

6

请检查这个

read -p "Continue? (y/n): " confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] || exit 1

5

受到@Mark和@Myrddin的答案启发,我创建了一个通用提示功能。

uniprompt(){
    while true; do
        echo -e "$1\c"
        read opt
        array=($2)
        case "${array[@]}" in  *"$opt"*) eval "$3=$opt";return 0;; esac
        echo -e "$opt is not a correct value\n"
    done
}

使用方法如下:

unipromtp "Select an option: (a)-Do one (x)->Do two (f)->Do three : " "a x f" selection
echo "$selection"

5

多项选择版本:

ask () {                        # $1=question $2=options
    # set REPLY
    # options: x=..|y=..
    while $(true); do
        printf '%s [%s] ' "$1" "$2"
        stty cbreak
        REPLY=$(dd if=/dev/tty bs=1 count=1 2> /dev/null)
        stty -cbreak
        test "$REPLY" != "$(printf '\n')" && printf '\n'
        (
            IFS='|'
            for o in $2; do
                if [ "$REPLY" = "${o%%=*}" ]; then
                    printf '\n'
                    break
                fi
            done
        ) | grep ^ > /dev/null && return
    done
}

例子:

$ ask 'continue?' 'y=yes|n=no|m=maybe'
continue? [y=yes|n=no|m=maybe] g
continue? [y=yes|n=no|m=maybe] k
continue? [y=yes|n=no|m=maybe] y
$

它将在脚本内部将REPLY设置为y

5

对于普通读者,可以在此处查看使用对话框命令的代码片段:https://dev59.com/WnVC5IYBdhLWcg3wpS3f#22893526 - Stephan

4
更加通用的说法是:
function menu(){
    title="Question time"
    prompt="Select:"
    options=("Yes" "No" "Maybe")
    echo "$title"
    PS3="$prompt"
    select opt in "${options[@]}" "Quit/Cancel"; do
        case "$REPLY" in
            1 ) echo "You picked $opt which is option $REPLY";;
            2 ) echo "You picked $opt which is option $REPLY";;
            3 ) echo "You picked $opt which is option $REPLY";;
            $(( ${#options[@]}+1 )) ) clear; echo "Goodbye!"; exit;;
            *) echo "Invalid option. Try another one.";continue;;
         esac
     done
     return
}

4

最简单的解决方案是这个没有巧妙技巧的一行代码:

read -p "press enter ..." y

这让人想起了经典的DOS系统的提示“按任意键继续”,不过这里只等待回车键,而非任何键。

确实,它没有为您提供三个选项:是、否、取消;但在像简单脚本中接受控制-C作为"否"或"取消"时,它是很有用的,例如:

#!/bin/sh
echo Backup this project
read -p "press enter ..." y
rsync -tavz . /media/hard_to_remember_path/backup/projects/yourproject/

因为您不喜欢需要记住难看的命令和路径,也不喜欢运行太快而没有机会在决定不运行所需脚本之前停止。
使用sh,需要使用命令行参数y,并且可以选择使用它来接收用户在按下回车键之前键入的答案,就像这样:
echo You entered $y

使用bash,您可以省略最后一个参数直接使用:
read -p "press enter ..."

1
read -p "press enter ..." y 中不需要 y - rych

3
作为一个喜欢一行命令的朋友,我使用了以下命令:
while [ -z $prompt ]; do read -p "Continue (y/n)?" choice;case "$choice" in y|Y ) prompt=true; break;; n|N ) exit 0;; esac; done; prompt=;

如果要进行长篇写作,它的工作方式如下:

while [ -z $prompt ];
  do read -p "Continue (y/n)?" choice;
  case "$choice" in
    y|Y ) prompt=true; break;;
    n|N ) exit 0;;
  esac;
done;
prompt=;

你能澄清一下 prompt 变量的用法吗?在我看来,它在一行代码之后就被清空了,那么你如何使用这行代码去执行任何操作呢? - Myrddin Emrys
当 while 循环结束后,提示符将被清除。因为我希望在之后初始化提示符变量(因为我将会更频繁地使用该语句)。在 shell 脚本中加入这行代码只有在键入 y|Y 后才会继续执行,而在键入 n|N 后就会退出,对于其他任何输入则会重复要求输入。 - ccDict

3

以下是我通常在脚本/函数中需要的内容:

  • 按 ENTER 键默认答案为“是”
  • 也接受字母 z(以防您使用 QWERTZ 布局)
  • 接受其他语言(例如“ja”,“Oui”等)
  • 在函数内部时正确处理退出操作
while true; do
    read -p "Continue [Y/n]? " -n 1 -r -e yn
    case "${yn:-Y}" in
        [YyZzOoJj]* ) echo; break ;;
        [Nn]* ) [[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 ;; # handle exits from shell or function but don't exit interactive shell
        * ) echo "Please answer yes or no.";;
    esac
done
echo "and off we go!"

3

是 / 否 / 取消

功能

#!/usr/bin/env bash
@confirm() {
  local message="$*"
  local result=''

  echo -n "> $message (Yes/No/Cancel) " >&2

  while [ -z "$result" ] ; do
    read -s -n 1 choice
    case "$choice" in
      y|Y ) result='Y' ;;
      n|N ) result='N' ;;
      c|C ) result='C' ;;
    esac
  done

  echo $result
}

使用方法

case $(@confirm 'Confirm?') in
  Y ) echo "Yes" ;;
  N ) echo "No" ;;
  C ) echo "Cancel" ;;
esac

使用干净的用户输入进行确认

功能

#!/usr/bin/env bash
@confirm() {
  local message="$*"
  local result=3

  echo -n "> $message (y/n) " >&2

  while [[ $result -gt 1 ]] ; do
    read -s -n 1 choice
    case "$choice" in
      y|Y ) result=0 ;;
      n|N ) result=1 ;;
    esac
  done

  return $result
}

使用方法

if @confirm 'Confirm?' ; then
  echo "Yes"
else
  echo "No"
fi

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