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

我想暂停外壳脚本中的输入,并提示用户选择。
标准的YesNoCancel类型的问题。如何在典型的bash提示符中完成此操作?

1252470 次浏览
echo "Please enter some input: "read input_variableecho "You entered: $input_variable"
inquire ()  {echo  -n "$1 [y/n]? "read answerfinish="-1"while [ "$finish" = '-1' ]dofinish="1"if [ "$answer" = '' ];thenanswer=""elsecase $answer iny | Y | yes | YES ) answer="y";;n | N | no | NO ) answer="n";;*) finish="-1";echo -n 'Invalid response -- please reenter:';read answer;;esacfidone}
... other stuff
inquire "Install now?"
...

在shell提示符下获取用户输入的最简单和最广泛可用的方法是#0命令。说明其使用的最佳方式是简单的演示:

while true; doread -p "Do you wish to install this program? " yncase $yn in[Yy]* ) make install; break;;[Nn]* ) exit;;* ) echo "Please answer yes or no.";;esacdone

另一种方法,指出Steven Huwig,是Bash的#0命令。这是使用select的相同示例:

echo "Do you wish to install this program?"select yn in "Yes" "No"; docase $yn inYes ) make install; break;;No ) exit;;esacdone

使用select,您不需要清理输入-它会显示可用的选项,然后您输入与您的选择对应的数字。它还会自动循环,因此如果它们提供无效输入,则无需while true循环重试。

此外,LéaGris她的回答中演示了一种使请求语言不可知的方法。调整我的第一个示例以更好地服务于多种语言可能如下所示:

set -- $(locale LC_MESSAGES)yesexpr="$1"; noexpr="$2"; yesword="$3"; noword="$4"
while true; doread -p "Install (${yesword} / ${noword})? " ynif [[ "$yn" =~ $yesexpr ]]; then make install; exit; fiif [[ "$yn" =~ $noexpr ]]; then exit; fiecho "Answer ${yesword} / ${noword}."done

显然,其他通信字符串在这里仍然未翻译(安装、回答),这需要在更完整的翻译中解决,但即使是部分翻译在许多情况下也会有帮助。

最后,请查看优秀的答案 byF. Hauri

我建议你使用对话框

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

dialog命令允许在shell脚本中使用窗口框,以使它们的使用更具交互性。

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

为此,Bash有选择

select result in Yes No Canceldoecho $resultdone
read -p "Are you alright? (y/n) " RESPif [ "$RESP" = "y" ]; thenecho "Glad to hear it"elseecho "You need more bash programming"fi

您可以使用内置的阅读命令;使用-p选项向用户提示问题。

从BASH4开始,您现在可以使用-i来建议答案:

read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATHecho $FILEPATH

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

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

read -e -p "List the content of your home dir ? [Y/n] " YN
[[ $YN == "y" || $YN == "Y" || $YN == "" ]] && ls -la ~/

使用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

还有你需要的其他东西

这里有一些我放在一起:

#!/bin/sh
promptyn () {while true; doread -p "$1 " yncase $yn in[Yy]* ) return 0;;[Nn]* ) return 1;;* ) echo "Please answer yes or no.";;esacdone}
if promptyn "is the sky blue?"; thenecho "yes"elseecho "no"fi

我是一个初学者,所以把这个与一粒盐,但它似乎工作。

yn() {if [[ 'y' == `read -s -n 1 -p "[y/n]: " Y; echo $Y` ]];then eval $1;else eval $2;fi }yn 'echo yes' 'echo no'yn 'echo absent no function works too!'

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

read -p "Are you sure? (y/n) " -n 1echoif [[ $REPLY =~ ^[Yy]$ ]]; thendo_somethingfi

多选版本:

ask () {                        # $1=question $2=options# set REPLY# options: x=..|y=..while $(true); doprintf '%s [%s] ' "$1" "$2"stty cbreakREPLY=$(dd if=/dev/tty bs=1 count=1 2> /dev/null)stty -cbreaktest "$REPLY" != "$(printf '\n')" && printf '\n'(IFS='|'for o in $2; doif [ "$REPLY" = "${o%%=*}" ]; thenprintf '\n'breakfidone) | grep ^ > /dev/null && returndone}

示例:

$ ask 'continue?' 'y=yes|n=no|m=maybe'continue? [y=yes|n=no|m=maybe] gcontinue? [y=yes|n=no|m=maybe] kcontinue? [y=yes|n=no|m=maybe] y$

它将REPLY设置为y(在脚本中)。

要获得一个漂亮的类似ncurses的输入框,请使用命令对话框,如下所示:

#!/bin/bashif (dialog --title "Message" --yesno "Want to do something risky?" 6 25)# message box will have the size 25x6 charactersthenecho "Let's do something risky"# do something riskyelseecho "Let's stay boring"fi

默认情况下,对话框包至少与SUSELinux一起安装。如下所示:对话框命令的作用

在我的情况下,我需要从下载的脚本中读取,即,

curl -Ss https://example.com/installer.sh | sh

在这种情况下,行read -r yn </dev/tty允许它读取输入。

printf "These files will be uploaded. Is this ok? (y/N) "read -r yn </dev/tty
if [ "$yn" = "y" ]; then   
# Yeselse   
# Nofi

受到@Mark和@Myrddin的答案的启发,我创建了这个函数用于通用提示

uniprompt(){while true; doecho -e "$1\c"read optarray=($2)case "${array[@]}" in  *"$opt"*) eval "$3=$opt";return 0;; esacecho -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" selectionecho "$selection"

一个一般问题至少有五个答案。

取决于

  • 兼容:可以在通用环境的糟糕系统上工作
  • 具体:使用所谓的巴什主义

如果你愿意的话

  • 简单的“在线”问题/答案(通用解决方案)
  • 漂亮的格式化界面,如或更多使用libgtk或libqt的图形…
  • 使用强大的readline历史功能

1. POSIX通用解决方案

您可以使用read命令,然后是if ... then ... else

printf 'Is this a good question (y/n)? 'read answer
# if echo "$answer" | grep -iq "^y" ;then
if [ "$answer" != "${answer#[Yy]}" ] ;then # this grammar (the #[] operator) means that the variable $answer where any Y or y in 1st position will be dropped if they exist.echo Yeselseecho Nofi

(感谢Adam Katz的评论:用一个更便携的测试取代了上面的测试,避免了一个分叉:)

POSIX,但单键功能

但是如果你不希望用户必须点击退货,你可以这样写:

编辑:正如@陈志立正确建议的那样,拯救 stty的配置可能比简单地强制它们理智要好。

printf '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 sttyif echo "$answer" | grep -iq "^y" ;thenecho Yeselseecho Nofi

备注:这是在9;sh&9;" aria-label="show questions tagged &9;sh&9;" rel="tag" aria-labelledby="sh-container">sh、9;bash&9;" aria-label="show questions tagged &9;bash&9;" rel="tag" aria-labelledby="bash-container">bash、下测试的!

相同,但显式等待yn

#/bin/shprintf 'Is this a good question (y/n)? 'old_stty_cfg=$(stty -g)stty raw -echoanswer=$( while ! head -c 1 | grep -i '[ny]' ;do true ;done )stty $old_stty_cfgif echo "$answer" | grep -iq "^y" ;thenecho Yeselseecho Nofi

使用专用工具

有许多工具是使用libncurseslibgtklibqt或其他图形库构建的。例如,使用whiptail

if whiptail --yesno "Is this a good question" 20 60 ;thenecho Yeselseecho Nofi

根据您的系统,您可能需要将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

其中20是对话框的行数高度,60是对话框的宽度。这些工具都有几乎相同语法。

DIALOG=whiptailif [ -x /usr/bin/gdialog ] ;then DIALOG=gdialog ; fiif [ -x /usr/bin/xdialog ] ;then DIALOG=xdialog ; fi...$DIALOG --yesno ...

2. Bash特定解决方案

基本符合方法

read -p "Is this a good question (y/n)? " answercase ${answer:0:1} iny|Y )echo Yes;;* )echo No;;esac

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

符合单键功能

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

read -n 1 -p "Is this a good question (y/n)? " answer

在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

3.专用工具的一些技巧

更复杂的对话框,超越简单的#0目的:

dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe

进度条:

dialog --gauge "Filling the tank" 20 60 0 < <(for i in {1..100};doprintf "XXX\n%d\n%(%a %b %T)T progress: %d\nXXX\n" $i -1 $isleep .033done)

小demo:

#!/bin/shwhile true ;do[ -x "$(which ${DIALOG%% *})" ] || DIALOG=dialogDIALOG=$($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" ) || exitclear;echo "Choosed: $DIALOG."for i in `seq 1 100`;dodate +"`printf "XXX\n%d\n%%a %%b %%T progress: %d\nXXX\n" $i $i`"sleep .0125done | $DIALOG --gauge "Filling the tank" 20 60 0$DIALOG --infobox "This is a simple info box\n\nNo action required" 20 60sleep 3if $DIALOG --yesno  "Do you like this demo?" 20 60 ;thenAnsYesNo=Yes; else AnsYesNo=No; fiAnsInput=$($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 60AnsCkLst=$($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 60done

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

5.使用readline的历史

示例:

#!/bin/bash
set -iHISTFILE=~/.myscript.historyhistory -chistory -r
myread() {read -e -p '> ' $1history -s ${!1}}trap 'history -a;exit' 0 1 2 3 6
while myread line;docase ${line%% *} inexit )  break ;;*    )  echo "Doing something with '$line'" ;;esacdone

这将在$HOME目录中创建一个文件.myscript.history,而不是使用readline的历史命令,如向上下来Ctrl+r等。

一个简单的方法是使用xargs -p或gnuparallel --interactive

我更喜欢xargs的行为,因为它像其他交互式unix命令一样在提示符之后立即执行每个命令,而不是收集最后运行的yess。(你可以在完成你想要的之后按Ctrl-C。)

例如,

echo *.xml | xargs -p -n 1 -J {} mv {} backup/
read -e -p "Enter your choice: " choice

-e选项使用户能够使用箭头键编辑输入。

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

read -e -i "yes" -p "Enter your choice: " choice

-i选项打印提示性输入。

作为一行命令的朋友,我使用了以下命令:

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" iny|Y ) prompt=true; break;;n|N ) exit 0;;esac;done;prompt=;

更通用的是:

function menu(){title="Question time"prompt="Select:"options=("Yes" "No" "Maybe")echo "$title"PS3="$prompt"select opt in "${options[@]}" "Quit/Cancel"; docase "$REPLY" in1 ) 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;;esacdonereturn}

您想要:

  • Bash内置命令(即可移植)
  • 检查TTY
  • 默认答案
  • 超时
  • 有色问句

片段

do_xxxx=y                      # In batch mode => Default is Yes[[ -t 0 ]] &&                  # If TTY => Prompt the questionread -n 1 -p $'\e[1;32mDo xxxx? (Y/n)\e[0m ' do_xxxx  # Store the answer in $do_xxxxif [[ $do_xxxx =~ ^(y|Y|)$ ]]  # Do if 'y' or 'Y' or emptythenxxxxfi

解释

  • [[ -t 0 ]] && read ...=>如果TTY调用命令read
  • 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;32mDo xxxx? (Y/n)\e[0m ' do_xxxx ||  # read 'fails' on timeoutdo_xxxx=n ; }                     # Timeout => answer Noif [[ $do_xxxx =~ ^(y|Y|)$ ]]thenxxxxfi

用最少的行数实现这一点的最简单方法如下:

read -p "<Your Friendly Message here> : y/n/cancel" CONDITION;
if [ "$CONDITION" == "y" ]; then# do something here!fi

if只是一个例子:如何处理这个变量取决于你。

在这种情况下,我已经使用了case语句几次,使用case语句是一个很好的方法。可以实现一个while循环,它封装了case块,利用布尔条件来保持对程序的更多控制,并满足许多其他要求。在满足所有条件后,可以使用break,它将控制传递回程序的主要部分。此外,为了满足其他条件,当然可以添加条件语句来伴随控制结构:case语句和可能的while循环。

使用case语句来满足您的请求的示例

#! /bin/sh
# For potential users of BSD, or other systems who do not# have a bash binary located in /bin the script will be directed to# a bourne-shell, e.g. /bin/sh
# NOTE: It would seem best for handling user entry errors or# exceptions, to put the decision required by the input# of the prompt in a case statement (case control structure),
echo Would you like us to perform the option: "(Y|N)"
read inPut
case $inPut in# echoing a command encapsulated by# backticks (``) executes the command"Y") echo `Do something crazy`;;# depending on the scenario, execute the other option# or leave as default"N") echo `execute another option`;;esac
exit

我注意到没有人发布一个答案,显示多行回声菜单用于如此简单的用户输入,所以这是我的尝试:

#!/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 3clear && ask_user
fi}
ask_user

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

是/否/取消

函数

#!/usr/bin/env bash@confirm() {local message="$*"local result=''
echo -n "> $message (Yes/No/Cancel) " >&2
while [ -z "$result" ] ; doread -s -n 1 choicecase "$choice" iny|Y ) result='Y' ;;n|N ) result='N' ;;c|C ) result='C' ;;esacdone
echo $result}

用法

case $(@confirm 'Confirm?') inY ) 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 ]] ; doread -s -n 1 choicecase "$choice" iny|Y ) result=0 ;;n|N ) result=1 ;;esacdone
return $result}

用法

if @confirm 'Confirm?' ; thenecho "Yes"elseecho "No"fi

回应其他人:

你不需要在BASH4中指定大小写,只需使用',,'来制作一个小写的var。此外,我非常不喜欢将代码放在读取块内,在IMO读取块之外获取结果并处理它。还包括一个'q'用于退出IMO。最后,为什么键入'yes'只需使用-n1并按y。

示例:用户可以按y/n和q退出。

ans=''while true; doread -p "So is MikeQ the greatest or what (y/n/q) ?" -n1 anscase ${ans,,} iny|n|q) break;;*) echo "Answer y for yes / n for no  or q for quit.";;esacdone
echo -e "\nAnswer = $ans"
if [[ "${ans,,}" == "q" ]] ; thenecho "OK Quitting, we will assume that he is"exit 0fi
if [[ "${ans,,}" == "y" ]] ; thenecho "MikeQ is the greatest!!"elseecho "No? MikeQ is not the greatest?"fi

仅限单键

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

  • 返回0=yes和1=no
  • 无需按回车键-只需一个字符
  • 可以按输入接受默认选择
  • 可以禁用默认选择以强制选择
  • 适用于zshbash

按回车键时默认为“否”

请注意,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]? XShow dangerous command [y/N]? yrm *

按回车键时默认为“是”

请注意,Y是大写的:

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

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

没有默认的输入-需要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]? kHere 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 -rn1printf '%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 defualtingfunction get_yes_keypress {local prompt="${1:-Are you sure [y/n]? }"local enter_return=$2local REPLY# [[ ! $prompt ]] && prompt="[y/n]? "while REPLY=$(get_keypress "$prompt"); do[[ $REPLY ]] && printf '\n' # $REPLY blank if user presses entercase "$REPLY" inY|y)  return 0;;N|n)  return 1;;'')   [[ $enter_return ]] && return "$enter_return"esacdone}
# 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上使用默认的REPLY,转换为小写并与一组带有表达式的变量进行比较。
该脚本还支持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)$ ]]; thenecho "Positive"fi

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

#!/usr/bin/env sh
# Getting LC_MESSAGES values into variables# shellcheck disable=SC2046 # Intended IFS splittingIFS='' 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 localeecho "$yesstr / $nostr ?"
# Read answerread -r yn
# Test answercase "$yn" in# match only work with the character class from the expression${yesexpr##^}) echo "answer $yesstr" ;;${noexpr##^}) echo "answer $nostr" ;;esac

编辑:正如他的评论中提到的@陈志立

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

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

LC_MESSAGES

#0#1语言环境关键字以及YESSTRNOSTR langinfo项以前用于匹配用户的肯定和否定响应。在POSIX.1-2008中,nostr0、nostr1、YESEXPRNOEXPR扩展正则表达式取代了它们。应用程序应使用通用的基于语言环境的消息传递工具来发出包含所需响应示例的提示消息。

或者使用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 ]]; doread -rp "$prompt" answerdone
if [[ -n "${BASH_REMATCH[1]}" ]]; thenecho $"You answered: Yes"elseecho $"No, was your answer."fi

使用语言环境提供的regexps匹配答案。

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

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

这是我通常在脚本/函数中需要的:

  • 默认答案为是,如果您按ENTER
  • 也接受z(如果你混淆了你在QWERTZ布局)
  • 接受其他语言("ja","Oui",…)
  • 如果你在函数内部,处理正确的出口
while true; doread -p "Continue [Y/n]? " -n 1 -r -e yncase "${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.";;esacdoneecho "and off we go!"

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

read -p "press enter ..." y

它让人想起经典的DOSHit any key to continue,除了它等待回车键,而不仅仅是任何键。

诚然,这并没有为您提供是否取消的三个选项,但在您接受Control-C作为否resp时它很有用。在简单的脚本中取消,例如:

#!/bin/shecho Backup this projectread -p "press enter ..." yrsync -tavz . /media/hard_to_remember_path/backup/projects/yourproject/

因为你不喜欢需要记住丑陋的命令和路径,但也不是运行太快的脚本,在你决定它不是你打算运行的脚本之前没有给你一个停止的机会。

看看这个

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

我为是/否问题制作了这个小脚本:https://github.com/optimistiCli/getans

示例:

#!/bin/bash
if ! getans.sh 'Shall we proceed?' y ; thenecho "User said “NO”"exit 1fi
echo "User said “YES”"# do something usefullexit 0

直接链接:https://github.com/optimistiCli/getans/raw/main/getans.sh

单行:

read -p "Continue? [Enter] → Yes, [Ctrl]+[C] → No."

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

使用PyInquirer的单行python替代方案

python3 -c 'import PyInquirer; print(PyInquirer.prompt([{"type":"confirm", "message":"Do you want to continue?", "name":"r"}]).get("r"))'

它支持是/否/取消(intr,CTRL+C)。

输入图片描述

你可以写一个函数来测试:

confirm() {local ans IFS=;while read -rp "$1" -n1 ans;do printf '\n';case $ans in [Yy]) return 0;;[Nn]) return 1;;esac;done;}; ## Usage: if confirm "Are you sure? "; then ...
if confirm "Does everything look ok...reboot now? [Y/n]"; thenecho "rebooting..."sleep 5rebootfi

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

  1. 很简单,只要几行贝壳
  2. 使用单个y/n按键(无需按回车键)
  3. 如果按回车键,默认为是
  4. 也可以使用大写Y/N

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

read -n1 -p "Continue? (Y/n) " confirm
if ! echo $confirm | grep '^[Yy]\?$'; thenexit 1fi

您可以修改该条件以仅在“yes”上运行(只需删除if语句中的!),或者如果您想在两个分支上运行代码,则添加else