如何在Linux shell脚本中提示是/否/取消输入?

Myr*_*rys 1352 linux bash shell scripting

我想在shell脚本中暂停输入,并提示用户进行选择.标准的"是,否或取消"类型问题.如何在典型的bash提示符中完成此操作?

Myr*_*rys 1514

在shell提示符下获取用户输入的最简单且最广泛可用的方法是read命令.说明其用法的最佳方式是一个简单的演示:

while true; do
    read -p "Do you wish to install this program?" yn
    case $yn in
        [Yy]* ) make install; break;;
        [Nn]* ) exit;;
        * ) echo "Please answer yes or no.";;
    esac
done
Run Code Online (Sandbox Code Playgroud)

Steven Huwig指出的另一种方法是Bash的select命令.以下是使用相同的示例select:

echo "Do you wish to install this program?"
select yn in "Yes" "No"; do
    case $yn in
        Yes ) make install; break;;
        No ) exit;;
    esac
done
Run Code Online (Sandbox Code Playgroud)

随着select你并不需要净化输入-它显示可用的选项,你键入相应的你的选择一个号码.它也会自动循环,因此while true如果它们提供无效输入,则无需重试循环.

另外,请查看F. Hauri 的优秀答案.

  • 在OS X Leopard中使用Bash,当我选择'no'时,我将`exit`改为`break`以防止关闭标签. (29认同)
  • 如果没有循环,为什么在“选择”中有一个“中断”? (3认同)

F. *_*uri 487

一个通用问题至少有五个答案.

取决于

  • 符合:可以在具有通用环境的不良系统上工作
  • 具体:使用所谓的bashisms

如果你想要的话

  • 简单的``在线''问题/答案(通用解决方案)
  • 相当格式化的接口,如使用libgtk或libqt的或更多图形...
  • 使用强大的readline历史记录功能

1. POSIX通用解决方案

您可以使用该read命令,然后执行以下操作if ... then ... else:

echo -n "Is this a good question (y/n)? "
read answer
Run Code Online (Sandbox Code Playgroud)

# if echo "$answer" | grep -iq "^y" ;then
Run Code Online (Sandbox Code Playgroud)

if [ "$answer" != "${answer#[Yy]}" ] ;then
    echo Yes
else
    echo No
fi
Run Code Online (Sandbox Code Playgroud)

(感谢Adam Katz的评论:将上面的测试替换为一个更便携的测试并避免使用一个分叉:)

POSIX,但是单一的关键功能

但如果您不希望用户必须点击Return,您可以写:

(编辑:正如@JonathanLeffler正确地建议的那样,保存 stty的配置可能比仅仅强迫他们理智更好.)

echo -n "Is this a good question (y/n)? "
old_stty_cfg=$(stty -g)
stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg # Careful playing with stty
if echo "$answer" | grep -iq "^y" ;then
    echo Yes
else
    echo No
fi
Run Code Online (Sandbox Code Playgroud)

注意:这是在,,,!

相同,但明确等待yn:

#/bin/sh
echo -n "Is this a good question (y/n)? "
old_stty_cfg=$(stty -g)
stty raw -echo
answer=$( while ! head -c 1 | grep -i '[ny]' ;do true ;done )
stty $old_stty_cfg
if echo "$answer" | grep -iq "^y" ;then
    echo Yes
else
    echo No
fi
Run Code Online (Sandbox Code Playgroud)

使用专用工具

有很多其使用内置的工具libncurses,libgtk,libqt或其他图形库.例如,使用whiptail:

if whiptail --yesno "Is this a good question" 20 60 ;then
    echo Yes
else
    echo No
fi
Run Code Online (Sandbox Code Playgroud)

根据您的系统,您可能需要更换whiptail另一个类似的工具:

dialog --yesno "Is this a good question" 20 60 && echo Yes

gdialog --yesno "Is this a good question" 20 60 && echo Yes

kdialog --yesno "Is this a good question" 20 60 && echo Yes
Run Code Online (Sandbox Code Playgroud)

20对话框的高度在哪里,行数60是对话框的宽度.这些工具都具有几乎相同的语法.

DIALOG=whiptail
if [ -x /usr/bin/gdialog ] ;then DIALOG=gdialog ; fi
if [ -x /usr/bin/xdialog ] ;then DIALOG=xdialog ; fi
...
$DIALOG --yesno ...
Run Code Online (Sandbox Code Playgroud)

2. Bash特定解决方案

基本的在线方法

read -p "Is this a good question (y/n)? " answer
case ${answer:0:1} in
    y|Y )
        echo Yes
    ;;
    * )
        echo No
    ;;
esac
Run Code Online (Sandbox Code Playgroud)

我更喜欢使用,case所以yes | ja | si | oui如果需要我甚至可以测试......

本着单键功能

在bash下,我们可以为read命令指定预期输入的长度:

read -n 1 -p "Is this a good question (y/n)? " answer
Run Code Online (Sandbox Code Playgroud)

在bash下,read命令接受超时参数,这可能很有用.

read -t 3 -n 1 -p "Is this a good question (y/n)? " answer
[ -z "$answer" ] && answer="Yes"  # if 'yes' have to be default choice
Run Code Online (Sandbox Code Playgroud)

专用工具的一些技巧

除了简单的yes - no目的之外,更复杂的对话框:

dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe
Run Code Online (Sandbox Code Playgroud)

进度条:

dialog --gauge "Filling the tank" 20 60 0 < <(
    for i in {1..100};do
        printf "XXX\n%d\n%(%a %b %T)T progress: %d\nXXX\n" $i -1 $i
        sleep .033
    done
) 
Run Code Online (Sandbox Code Playgroud)

小演示:

#!/bin/sh
while true ;do
    [ -x "$(which ${DIALOG%% *})" ] || DIALOG=dialog
    DIALOG=$($DIALOG --menu "Which tool for next run?" 20 60 12 2>&1 \
            whiptail       "dialog boxes from shell scripts" >/dev/tty \
            dialog         "dialog boxes from shell with ncurses" \
            gdialog        "dialog boxes from shell with Gtk" \
            kdialog        "dialog boxes from shell with Kde" ) || exit
    clear;echo "Choosed: $DIALOG."
    for i in `seq 1 100`;do
        date +"`printf "XXX\n%d\n%%a %%b %%T progress: %d\nXXX\n" $i $i`"
        sleep .0125
      done | $DIALOG --gauge "Filling the tank" 20 60 0
    $DIALOG --infobox "This is a simple info box\n\nNo action required" 20 60
    sleep 3
    if $DIALOG --yesno  "Do you like this demo?" 20 60 ;then
        AnsYesNo=Yes; else AnsYesNo=No; fi
    AnsInput=$($DIALOG --inputbox "A text:" 20 60 "Text here..." 2>&1 >/dev/tty)
    AnsPass=$($DIALOG --passwordbox "A secret:" 20 60 "First..." 2>&1 >/dev/tty)
    $DIALOG --textbox /etc/motd 20 60
    AnsCkLst=$($DIALOG --checklist "Check some..." 20 60 12 \
        Correct "This demo is useful"        off \
        Fun        "This demo is nice"        off \
        Strong        "This demo is complex"        on 2>&1 >/dev/tty)
    AnsRadio=$($DIALOG --radiolist "I will:" 20 60 12 \
        " -1" "Downgrade this answer"        off \
        "  0" "Not do anything"                on \
        " +1" "Upgrade this anser"        off 2>&1 >/dev/tty)
    out="Your answers:\nLike: $AnsYesNo\nInput: $AnsInput\nSecret: $AnsPass"
    $DIALOG --msgbox "$out\nAttribs: $AnsCkLst\nNote: $AnsRadio" 20 60
  done
Run Code Online (Sandbox Code Playgroud)

更多样品?看看使用whiptail选择USB设备USB可移动存储选择器:USBKeyChooser

5.使用readline的历史记录

例:

#!/bin/bash

set -i
HISTFILE=~/.myscript.history
history -c
history -r

myread() {
    read -e -p '> ' $1
    history -s ${!1}
}
trap 'history -a;exit' 0 1 2 3 6

while myread line;do
    case ${line%% *} in
        exit )  break ;;
        *    )  echo "Doing something with '$line'" ;;
      esac
  done
Run Code Online (Sandbox Code Playgroud)

这将创建一个文件.myscript.history$HOME目录中,比你能使用输入行的历史命令,比如Up, Down,Ctrl+ r等.

  • 您可以将`case`用于POSIX以及bash(使用通配符条件而不是bash子字符串:`case $ answer in; [Yy]*)echo Yes ;;`),但我更喜欢使用条件语句,赞成`["$ answer"!="$ {answer#[Yy]}"]`超过你的'echo'$ answer"| grep -iq ^ y`.它更便携(一些非GNU greps没有正确实现`-q`)并且它没有系统调用.`$ {answer#[Yy]}`使用参数扩展从`$ answer`的开头删除`Y`或`y`,当存在任何一个时导致不等式.这适用于任何POSIX shell(dash,ksh,bash,zsh,busybox等). (5认同)
  • 注意`stty`提供了`-g`选项:`old_stty = $(stty -g); stty raw -echo; ...; stty"$ old_stty"`.这将完全恢复设置,这可能与`stty -sane`相同或不同. (4认同)
  • `read answer`将在空格和换行符之前解释反斜杠,否则会剥离它们很少用于它们.根据[SC2162](https://github.com/koalaman/shellcheck/wiki/SC2162)使用`read -r answer`. (3认同)
  • @CarterPape 是的,这是个笑话!但在这个详细的答案中,你可能会发现很多技巧(第二点至少有3种不同的方法)!而且……从大约5年到现在,你第一个讲述我的计数方法!;-)) (2认同)

Pis*_*tos 348

echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
Run Code Online (Sandbox Code Playgroud)

  • 我不同意,因为它只实现了DOS中"是,否,取消"对话框的一部分功能.它无法实现的部分是输入检查...循环,直到收到有效的答案. (22认同)
  • 但原始问题描述未更改,并始终要求对是/否/取消提示进行响应.标题已经更新,比我原来的标题更清晰,但问题描述总是很清楚(在我看来). (7认同)
  • (最初的问题标题是“如何在 Linux shell 脚本中提示输入?”) (4认同)

yPh*_*hil 163

您可以使用内置的read命令; 使用该-p选项可向用户提示问题.

从BASH4开始,您现在可以使用-i建议答案,因此用户只需按下-e即可输入:

read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATH
echo $FILEPATH
Run Code Online (Sandbox Code Playgroud)

(但请记住使用"readline"选项-p允许使用箭头键进行行编辑)

如果你想要一个"是/否"逻辑,你可以这样做:

read -e -p "
List the content of your home dir ? [Y/n] " YN

[[ $YN == "y" || $YN == "Y" || $YN == "" ]] && ls -la ~/
Run Code Online (Sandbox Code Playgroud)

  • 应该注意的是,`FILEPATH`是您选择的变量名,并通过命令提示符的答案进行设置.因此,如果您要运行`vlc"$ FILEPATH",例如,`vlc`将打开该文件. (5认同)

Ste*_*wig 105

Bash已经选择了这个目的.

select result in Yes No Cancel
do
    echo $result
done
Run Code Online (Sandbox Code Playgroud)

  • +1 Geniously简单的解决方案.唯一的事情:这将提示并提示并提示......直到你在里面添加`exit` :) (18认同)
  • 但是,这不允许您输入y或n.您可以通过输入1 2或3进行选择. (12认同)
  • (德皇:要打破它,只需输入EOT:`按Ctrl-D'但当然,使用它需要休息或身体的退出真正的代码.) (5认同)
  • `exit`将一起退出脚本,`break`将只退出你所在的循环(如果你在`while`或`case`循环) (2认同)

小智 56

read -p "Are you alright? (y/n) " RESP
if [ "$RESP" = "y" ]; then
  echo "Glad to hear it"
else
  echo "You need more bash programming"
fi
Run Code Online (Sandbox Code Playgroud)


mpe*_*pen 36

这是我放在一起的东西:

#!/bin/sh

promptyn () {
    while true; do
        read -p "$1 " yn
        case $yn in
            [Yy]* ) return 0;;
            [Nn]* ) return 1;;
            * ) echo "Please answer yes or no.";;
        esac
    done
}

if promptyn "is the sky blue?"; then
    echo "yes"
else
    echo "no"
fi
Run Code Online (Sandbox Code Playgroud)

我是一个初学者,所以带上一粒盐,但似乎有效.

  • 如果你将`case $ yn in`改为`case $ {yn: - $ 2} in`那么你可以使用第二个参数作为默认值Y或N. (9认同)

小智 32

inquire ()  {
  echo  -n "$1 [y/n]? "
  read answer
  finish="-1"
  while [ "$finish" = '-1' ]
  do
    finish="1"
    if [ "$answer" = '' ];
    then
      answer=""
    else
      case $answer in
        y | Y | yes | YES ) answer="y";;
        n | N | no | NO ) answer="n";;
        *) finish="-1";
           echo -n 'Invalid response -- please reenter:';
           read answer;;
       esac
    fi
  done
}

... other stuff

inquire "Install now?"

...
Run Code Online (Sandbox Code Playgroud)

  • 如果案例开关是硬编码的,为什么我们提供'y'和'n'作为查询()的参数?那只是要求滥用.它们是固定参数,不是可变的,所以第2行的回声应该是:echo -n"$ 1 [Y/N]?"它们不能改变,因此不应该提供它们. (10认同)
  • @MateuszPiotrowski自从我发表评论以来,答案已经过编辑和改进.您可以点击上面的"已编辑的12月23日"链接查看此答案的所有过去版本.早在2008年,代码就完全不同了. (4认同)
  • 在每行的开头放置四个空格以保留代码的格式。 (2认同)

oli*_*bre 27

你要:

  • Bash内置命令(即便携式)
  • 检查TTY
  • 默认答案
  • 超时
  • 有色的问题

片段

do_xxxx=y                      # In batch mode => Default is Yes
[[ -t 0 ]] &&                  # If TTY => Prompt the question
read -n 1 -p $'\e[1;32m
Do xxxx? (Y/n)\e[0m ' do_xxxx  # Store the answer in $do_xxxx
if [[ $do_xxxx =~ ^(y|Y|)$ ]]  # Do if 'y' or 'Y' or empty
then
    xxxx
fi
Run Code Online (Sandbox Code Playgroud)

说明

  • [[ -t 0 ]] && read ...=> read如果TTY,则调用命令
  • read -n 1 =>等一个字符
  • $'\e[1;32m ... \e[0m '=>以绿色打印
    (绿色很好,因为白色/黑色背景都可读)
  • [[ $do_xxxx =~ ^(y|Y|)$ ]] => bash正则表达式

超时=>默认答案为否

do_xxxx=y
[[ -t 0 ]] && {                   # Timeout 5 seconds (read -t 5)
read -t 5 -n 1 -p $'\e[1;32m
Do xxxx? (Y/n)\e[0m ' do_xxxx ||  # read 'fails' on timeout
do_xxxx=n ; }                     # Timeout => answer No
if [[ $do_xxxx =~ ^(y|Y|)$ ]]
then
    xxxx
fi
Run Code Online (Sandbox Code Playgroud)


Apu*_*kar 24

使用最少行数实现此目的的最简单方法如下:

read -p "<Your Friendly Message here> : y/n/cancel" CONDITION;

if [ "$CONDITION" == "y" ]; then
   # do something here!
fi
Run Code Online (Sandbox Code Playgroud)

if只是一个例子:由你决定如何处理这个变量.


小智 18

使用read命令:

echo Would you like to install? "(Y or N)"

read x

# now check if $x is "y"
if [ "$x" = "y" ]; then
    # do something here!
fi
Run Code Online (Sandbox Code Playgroud)

然后你需要的所有其他东西


Den*_*nis 17

此解决方案读取单个字符并在yes响应上调用函数.

read -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    do_something      
fi
Run Code Online (Sandbox Code Playgroud)

  • @Jav echo在您的回复后会打印换行符。如果没有它,下一个要打印的内容将在您在同一行上回复后立即出现。尝试删除`echo`自己看看。 (2认同)

Léa*_*ris 16

可以在 POSIX shell 中处理语言环境感知的“是/否选择”;通过使用LC_MESSAGESlocale 类别的条目,witch 提供了现成的 RegEx 模式来匹配输入,以及用于本地化 Yes No 的字符串。

#!/usr/bin/env sh

# Getting LC_MESSAGES values into variables
# shellcheck disable=SC2046 # Intended IFS splitting
IFS='
' set -- $(locale LC_MESSAGES)

yesexpr="$1"
noexpr="$2"
yesstr="$3"
nostr="$4"
messages_codeset="$5" # unused here, but kept as documentation

# Display Yes / No ? prompt into locale
echo "$yesstr / $nostr ?"

# Read answer
read -r yn

# Test answer
case "$yn" in
# match only work with the character class from the expression
  ${yesexpr##^}) echo "answer $yesstr" ;;
  ${noexpr##^}) echo "answer $nostr" ;;
esac
Run Code Online (Sandbox Code Playgroud)

编辑:正如@Urhixidur他的评论中提到的:

不幸的是,POSIX 只指定了前两个(yesexpr 和 noexpr)。在 Ubuntu 16 上, yesstr 和 nostr 为空。

参见:https : //www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06

LC_MESSAGES

yesstrnostr现场的关键字和YESSTRNOSTRlanginfo项目以前用于匹配用户的肯定和否定响应。在 POSIX.1-2008 中yesexprnoexprYESEXPR、 和NOEXPR扩展正则表达式已经取代了它们。应用程序应该使用基于区域设置的通用消息传递工具来发出提示消息,其中包括示例所需的响应。

或者以 Bash 方式使用语言环境:

#!/usr/bin/env bash

IFS=$'\n' read -r -d '' yesexpr noexpr _ < <(locale LC_MESSAGES)

printf -v yes_or_no_regex "(%s)|(%s)" "$yesexpr" "$noexpr"

printf -v prompt $"Please answer Yes (%s) or No (%s): " "$yesexpr" "$noexpr"

declare -- answer=;

until [[ "$answer" =~ $yes_or_no_regex ]]; do
  read -rp "$prompt" answer
done

if [[ -n "${BASH_REMATCH[1]}" ]]; then
  echo $"You answered: Yes"
else
  echo $"No, was your answer."
fi
Run Code Online (Sandbox Code Playgroud)

使用语言环境提供的正则表达式匹配答案。

要翻译剩余的消息,请使用bash --dump-po-strings scriptname输出 po 字符串以进行本地化:

#: scriptname:8
msgid "Please answer Yes (%s) or No (%s): "
msgstr ""
#: scriptname:17
msgid "You answered: Yes"
msgstr ""
#: scriptname:19
msgid "No, was your answer."
msgstr ""
Run Code Online (Sandbox Code Playgroud)

  • 可是等等!还有更糟糕的消息!bash case 语句表达式不是正则表达式,它们是文件名表达式。因此,Ubuntu 16 的 yesexpr 和 noexpr(分别为“^[yY].*”和“^[nN].*”)将因嵌入句点而完全失败。在正则表达式中,“.*”表示“任何非换行符,零次或多次”。但在 case 语句中,它是一个字面的“。” 后跟任意数量的字符。 (2认同)

Jah*_*hid 12

read -e -p "Enter your choice: " choice
Run Code Online (Sandbox Code Playgroud)

-e选项使用户可以使用箭头键编辑输入.

如果您想使用建议作为输入:

read -e -i "yes" -p "Enter your choice: " choice
Run Code Online (Sandbox Code Playgroud)

-i 选项打印暗示输入.


Wal*_*r A 12

您可以在REPLY上使用默认值read,将其转换为小写并与带有表达式的一组变量进行比较。
该脚本还支持ja/ si/oui

read -rp "Do you want a demo? [y/n/c] "

[[ ${REPLY,,} =~ ^(c|cancel)$ ]] && { echo "Selected Cancel"; exit 1; }

if [[ ${REPLY,,} =~ ^(y|yes|j|ja|s|si|o|oui)$ ]]; then
   echo "Positive"
fi
Run Code Online (Sandbox Code Playgroud)


Eri*_*kis 11

这个问题有很多好的答案,但从我看来,没有一个是我的理想答案,即:

  1. 简单点,几行shell就可以了
  2. 使用单个 y/n 按键(无需按 Enter)
  3. 如果您直接按 Enter 键,则默认为 yes
  4. 也可使用大写 Y/N

这是我的版本,它具有这些属性:

read -n1 -p "Continue? (Y/n) " confirm

if ! echo $confirm | grep '^[Yy]\?$'; then
  exit 1
fi
Run Code Online (Sandbox Code Playgroud)

您可以将该条件修改为仅在“yes”上运行(只需删除!语句中的if)或添加elseif 您想在两个分支上运行代码。


use*_*932 10

很抱歉在这么老的帖子上发帖.几周前我遇到了类似的问题,在我的情况下,我需要一个解决方案,它也可以在一个在线安装程序脚本中工作,例如:curl -Ss https://raw.github.com/_____/installer.sh | bash

使用read yesno < /dev/tty对我来说很好:

echo -n "These files will be uploaded. Is this ok? (y/n) "
read yesno < /dev/tty

if [ "x$yesno" = "xy" ];then

   # Yes
else

   # No
fi
Run Code Online (Sandbox Code Playgroud)

希望这有助于某人.


Ctr*_*l-C 10

单线:

\n
read -p "Continue? [Enter] \xe2\x86\x92 Yes, [Ctrl]+[C] \xe2\x86\x92 No."\n
Run Code Online (Sandbox Code Playgroud)\n

这假设“否”和“取消”具有相同的结果,因此没有理由以不同的方式对待它们。

\n


Tho*_*erk 9

要获得一个很好的类似ncurses的输入框,请使用如下命令对话框:

#!/bin/bash
if (dialog --title "Message" --yesno "Want to do something risky?" 6 25)
# message box will have the size 25x6 characters
then 
    echo "Let's do something risky"
    # do something risky
else 
    echo "Let's stay boring"
fi
Run Code Online (Sandbox Code Playgroud)

默认情况下,对话框软件包至少安装在SUSE Linux中.


Tom*_*ale 9

仅限单键按键

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

  • 返回0=是和1=否
  • 无需按下输入 - 只需一个字符
  • 可以按下enter接受默认选择
  • 可以禁用默认选项以强制选择
  • 适用于zshbash.

按Enter键时默认为"no"

请注意,这N是资本.按Enter键,接受默认值:

$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?
Run Code Online (Sandbox Code Playgroud)

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

重新提示,直到给出有效的回复:

$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *
Run Code Online (Sandbox Code Playgroud)

按Enter键时默认为"是"

请注意,Y大写:

$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *
Run Code Online (Sandbox Code Playgroud)

上面,我只是按了回车键,所以命令运行了.

没有默认值enter- 要求yn

$ get_yes_keypress "Here you cannot press enter. Do you like this [y/n]? "
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
Run Code Online (Sandbox Code Playgroud)

在这里,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
}
Run Code Online (Sandbox Code Playgroud)


Yok*_*kai 6

我注意到没有人发布这样一个简单的用户输入显示多行回显菜单的答案,因此我可以这样做:

#!/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
Run Code Online (Sandbox Code Playgroud)

发布此方法是为了希望有人发现它有用且节省时间。


Sam*_*ape 6

检查这个

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


Osa*_*eed 5

我建议你使用对话框...

Linux 学徒:使用对话框改进 Bash Shell 脚本

对话框命令允许在 shell 脚本中使用窗口框,从而使其使用更具交互性。

它简单易用,还有一个名为 gdialog 的 gnome 版本,它采用完全相同的参数,但在 X 上显示 GUI 风格。


Ern*_*t A 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
}
Run Code Online (Sandbox Code Playgroud)

例子:

$ 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
$
Run Code Online (Sandbox Code Playgroud)

它将设置REPLYy(在脚本内)。


mig*_*uel 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
}
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

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