我想暂停 shell 脚本中的输入,并提示用户选择。
标准 Yes
、 No
或 Cancel
类型问题。
如何在典型的 bash 提示符中完成此操作?
原文由 Myrddin Emrys 发布,翻译遵循 CC BY-SA 4.0 许可协议
我想暂停 shell 脚本中的输入,并提示用户选择。
标准 Yes
、 No
或 Cancel
类型问题。
如何在典型的 bash 提示符中完成此操作?
原文由 Myrddin Emrys 发布,翻译遵循 CC BY-SA 4.0 许可协议
根据
如果你想
您可以使用 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 Yes
else
echo No
fi
(感谢 Adam Katz 的评论:将上面的测试替换为更便携且避免使用分叉的测试:)
但是,如果您不希望用户必须点击 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 echo "$answer" | grep -iq "^y" ;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 echo "$answer" | grep -iq "^y" ;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
在 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
更复杂的对话框,超越简单 yes - no
用途:
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" ) || 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
更多样品?看看 使用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
等。
原文由 F. Hauri - Give Up GitHub 发布,翻译遵循 CC BY-SA 4.0 许可协议
7 回答5.2k 阅读
4 回答4k 阅读
2 回答5.9k 阅读✓ 已解决
2 回答2.5k 阅读✓ 已解决
1 回答2.3k 阅读✓ 已解决
2 回答782 阅读✓ 已解决
2 回答3.2k 阅读
在 shell 提示符下获取用户输入的最简单和最广泛可用的方法是
read
命令。说明其使用的最好方法是一个简单的演示:Steven Huwig 指出 的另一种方法是 Bash 的
select
命令。这是使用select
的相同示例:使用
select
您不需要清理输入 - 它会显示可用的选项,然后您键入与您的选择相对应的数字。它还会自动循环,因此如果输入无效,则无需while true
循环重试。此外, Léa Gris 在 她的回答 中演示了一种使请求语言不可知的方法。调整我的第一个示例以更好地服务于多种语言可能如下所示:
显然,其他通信字符串在此处仍未翻译(安装、回答),这需要在更完整的翻译中解决,但在许多情况下,即使是部分翻译也会有所帮助。
最后,请查看 F. Hauri 的 出色回答。