我想暂停shell脚本中的输入,并提示用户进行选择,例如标准的“是”、“否”或“取消”类型的问题。在典型的bash提示符下,如何实现这一点?
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
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
select
时,您无需对输入进行清理-它会显示可用选项,并且您只需键入与您的选择相对应的数字。它还会自动循环,因此无需使用while true
循环来重试,如果输入无效。set -- $(locale LC_MESSAGES)
yesexpr="$1"; noexpr="$2"; yesword="$3"; noword="$4"
while true; do
read -p "Install (${yesword} / ${noword})? " yn
if [[ "$yn" =~ $yesexpr ]]; then make install; exit; fi
if [[ "$yn" =~ $noexpr ]]; then exit; fi
echo "Answer ${yesword} / ${noword}."
done
exit
更改为break
,以防在选择“否”时关闭选项卡。 - Trey Piepmeierselect
中要使用break
? - Jayenssh my-server 'path/to/myscript.sh'
。以这种方式执行时,“read -p”命令的提示文本不会显示出来。但是,echo
命令的输出确实可见。因此,对我而言,更好的解决方案是使用echo -n“是否执行某项操作?”
,然后跟上read yn
。 - Travesty3取决于
如果你想的话
您可以使用read
命令,后跟if ... then ... else
:
printf 'Is this a good question (y/n)? '
read answer
if [ "$answer" != "${answer#[Yy]}" ] ;then
echo Yes
else
echo No
fi
(感谢Adam Katz的评论:用更便携且避免一个fork的新测试替换了上面的测试)
但是,如果您不希望用户必须按Return键,则可以编写:
(编辑:正如@JonathanLeffler所建议的那样,保存 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 stty
if [ "$answer" != "${answer#[Yy]}" ];then
echo Yes
else
echo No
fi
注意:此代码已在sh、bash、ksh、dash和busybox下测试通过!
相同的代码,但需要明确等待y或n:
#/bin/sh
printf '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 [ "$answer" != "${answer#[Yy]}" ];then
echo Yes
else
echo No
fi
有许多使用libncurses
、libgtk
、libqt
或其他图形库构建的工具。例如,使用whiptail
:
if whiptail --yesno "Is this a good question" 20 60 ;then
echo Yes
else
echo No
fi
根据您的系统,您可能需要使用其他类似工具来替换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=whiptail
if [ -x /usr/bin/gdialog ] ;then DIALOG=gdialog ; fi
if [ -x /usr/bin/xdialog ] ;then DIALOG=xdialog ; fi
...
$DIALOG --yesno ...
read -p "Is this a good question (y/n)? " answer
case ${answer:0:1} in
y|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
read
命令接受一个timeout参数,这可能会很有用。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
i=6 ;while ((i-->1)) &&
! read -sn 1 -t 1 -p $'\rIs this a good question (Y/n)? '$i$'..\e[3D' answer;do
:;done ;[[ $answer == [nN] ]] && answer=No || answer=Yes ;echo "$answer "
更复杂的对话框,超出简单的是 - 否
的用途:
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};do
printf "XXX\n%d\n%(%a %b %T)T progress: %d\nXXX\n" $i -1 $i
sleep .033
done
)
小演示:
#!/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" ) || break
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
需要更多示例吗?请查看使用whiptail选择USB设备和USB可移动存储器选择器:USBKeyChooser
示例:
#!/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
$HOME
目录中创建一个名为.myscript.history
的文件,然后您可以使用readline的历史命令,例如Up,Down,Ctrl+r等。stty
提供 -g
选项以供使用:old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty"
。这会恢复设置为它们原来的状态,可能与 stty -sane
的设置相同或不同。 - Jonathan Lefflercase
(使用通配符条件而不是Bash子字符串:case $answer in; [Yy]* ) echo Yes ;;
),但我更喜欢使用条件语句,更喜欢 [ "$answer" != "${answer#[Yy]}" ]
而非您的 echo "$answer" | grep -iq ^y
。 这种方式更具可移植性(一些非GNU grep未正确实现-q
)并且没有系统调用。${answer#[Yy]}
使用参数扩展从$answer
开头删除Y
或y
,当其中任何一个存在时会导致不等式。这适用于任何POSIX shell(dash,ksh,bash,zsh,busybox等)。 - Adam Katzecho "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
-p
选项提示用户提问。-i
来建议答案:read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(但是要记得使用“readline”选项-e
,以允许使用箭头键进行行编辑)
如果你想要"是/否"逻辑,可以这样做:
read -e -p "
List the content of your home dir ? [Y/n] " YN
[[ $YN == "y" || $YN == "Y" || $YN == "" ]] && ls -la ~/
FILEPATH
是您选择的变量名称,并使用命令提示符的答案进行设置。例如,如果您随后运行 vlc "$FILEPATH"
,那么 vlc
将打开该文件。 - Ken Sharp-e
有什么好处(简单的是/否)? - JBallin-e
标志/选项,您可能(根据实现)无法输入“y”,然后改变主意并将其替换为“n”(或其他任何内容);
在记录命令时,单独列出选项有助于提高可读性/清晰度,以及其他原因。 - yPhilBash有select命令可用于此目的。以下是如何在脚本中使用:
select result in Yes No Cancel
do
echo $result
done
这是使用它的样子:
$ bash examplescript.sh
1) Yes
2) No
3) Cancel
#? 1
Yes
#? 2
No
#? 3
Cancel
#?
exit
:) - kaiserCtrl-D
。但是,实际上在使用它的真正代码中,需要在函数体内添加break或exit语句。 - Zorawarexit
将完全退出脚本,break
只会退出当前循环(如果你在 while
或 case
循环中)。 - wranvaudread -p "Are you alright? (y/n) " RESP
if [ "$RESP" = "y" ]; then
echo "Glad to hear it"
else
echo "You need more bash programming"
fi
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?"
...
echo -n "$1 [Y/N]? "
既然它们无法更改,就不应该提供它们作为参数。 - Myrddin Emrys这是我整理的一些东西:
#!/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
我是初学者,所以这只是我的一些看法,但它似乎有效。
case $yn in
改为 case ${yn:-$2} in
,那么你可以使用第二个参数作为默认值,即 Y 或 N。 - jchookcase $yn
更改为case "${yn:-Y}"
,以使是作为默认选项。 - rubo77if
语句!但是在使用 set -e
的脚本中似乎无法正常工作。你有什么解决方法吗? - winklerrrset -e
看起来还不错。您确定脚本中没有其他错误吗? - mpenanswer="$(promptyn "is the sky blue?")"
。我认为这导致了“错误”。 - winklerrrdo_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
[[ -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;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
if [[ $do_xxxx =~ ^(y|Y|)$ ]]
应该是:
if [[ $do_xxxx =~ ^(y|Y)$ ]]
- Vladimir Yakovenko最简单的方法,且所需代码最少的方式如下:
read -p "<Your Friendly Message here> : y/n/cancel" CONDITION;
if [ "$CONDITION" == "y" ]; then
# do something here!
fi
if
只是一个例子:如何处理这个变量取决于你。
[yn]
选项,则大写字母是默认值。即[Yn]
默认为“yes”,[yN]
默认为“no”。请参见https://ux.stackexchange.com/a/40445/43532 - Tyzoidread
命令进行提示。 - smac89bash
中暂停的规范方式。提供的结果可以轻松转移。 - Cadoiz