[英]How do I prompt for Yes/No/Cancel input in a Linux shell script?
I want to pause input in a shell script, and prompt the user for choices.我想暂停 shell 脚本中的输入,并提示用户选择。
The standard Yes
, No
, or Cancel
type question.标准
Yes
、 No
或Cancel
类型的问题。
How do I accomplish this in a typical bash prompt?如何在典型的 bash 提示符中完成此操作?
The simplest and most widely available method to get user input at a shell prompt is the read
command.在 shell 提示符下获取用户输入的最简单和最广泛可用的方法是
read
命令。 The best way to illustrate its use is a simple demonstration:说明其使用的最好方法是一个简单的演示:
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
Another method, pointed out by Steven Huwig , is Bash's select
command. Steven Huwig指出的另一种方法是 Bash 的
select
命令。 Here is the same example using 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
With select
you don't need to sanitize the input – it displays the available choices, and you type a number corresponding to your choice.使用
select
您不需要清理输入 - 它会显示可用的选项,然后您键入与您的选择相对应的数字。 It also loops automatically, so there's no need for a while true
loop to retry if they give invalid input.它还会自动循环,因此如果它们提供无效输入,则无需使用
while true
循环重试。
Also, Léa Gris demonstrated a way to make the request language agnostic in her answer .此外, Léa Gris在她的回答中演示了一种使请求语言不可知的方法。 Adapting my first example to better serve multiple languages might look like this:
调整我的第一个示例以更好地服务于多种语言可能如下所示:
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
Obviously other communication strings remain untranslated here (Install, Answer) which would need to be addressed in a more fully completed translation, but even a partial translation would be helpful in many cases.显然,其他通信字符串在此处仍未翻译(安装、回答),这需要在更完整的翻译中解决,但在许多情况下,即使是部分翻译也会有所帮助。
Finally, please check out the excellent answer by F. Hauri .最后,请查看F. Hauri的出色回答。
Depending on根据
and if you want如果你想
You could use the read
command, followed by if ... then ... else
:您可以使用
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
(Thanks to Adam Katz's comment : Replaced the test above with one that is more portable and avoids one fork:) (感谢Adam Katz 的评论:将上面的测试替换为更便携且避免使用分叉的测试:)
But if you don't want the user to have to hit Return , you could write:但是,如果您不希望用户必须点击Return ,您可以编写:
( Edited: As @JonathanLeffler rightly suggest, saving stty's configuration could be better than simply force them to sane .) (已编辑:正如@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
Note: This was tested under sh , bash , ksh , dash and busybox !注意:这是在sh 、 bash 、 ksh 、 dash和busybox下测试的!
Same, but waiting explicitly for y or n :相同,但明确等待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
There are many tools which were built using libncurses
, libgtk
, libqt
or other graphical libraries.有许多使用
libncurses
、 libgtk
、 libqt
或其他图形库构建的工具。 For example, using whiptail
:例如,使用
whiptail
:
if whiptail --yesno "Is this a good question" 20 60 ;then
echo Yes
else
echo No
fi
Depending on your system, you may need to replace whiptail
with another similiar tool:根据您的系统,您可能需要用另一个类似的工具替换
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
where 20
is height of dialog box in number of lines and 60
is width of the dialog box.其中
20
是对话框的行数高度, 60
是对话框的宽度。 These tools all have near same syntax.这些工具都具有几乎相同的语法。
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
I prefer to use case
so I could even test for yes | ja | si | oui
我更喜欢用
case
,所以我什至可以测试yes | ja | si | oui
yes | ja | si | oui
yes | ja | si | oui
if needed... yes | ja | si | oui
如果需要...
Under bash, we can specify the length of intended input for for the read
command:在 bash 下,我们可以为
read
命令指定预期输入的长度:
read -n 1 -p "Is this a good question (y/n)? " answer
Under bash, read
command accepts a timeout parameter, which could be useful.在 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
More sophisticated dialog boxes, beyond simple yes - no
purposes:更复杂的对话框,除了简单的
yes - no
目的:
dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe
Progress bar:进度条:
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
)
Little demo:小演示:
#!/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
More samples?更多样品? Have a look at Using whiptail for choosing USB device and USB removable storage selector: USBKeyChooser
看看使用whiptail选择USB设备和USB可移动存储选择器:USBKeyChooser
Example:例子:
#!/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
This will create a file .myscript.history
in your $HOME
directory, than you could use readline's history commands, like Up , Down , Ctrl + r and others.这将在您的
$HOME
目录中创建一个文件.myscript.history
,而不是您可以使用 readline 的历史命令,如Up 、 Down 、 Ctrl + r等。
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
You can use the built-in read command ;您可以使用内置的读取命令; Use the
-p
option to prompt the user with a question.使用
-p
选项向用户提示问题。
Since BASH4, you can now use -i
to suggest an answer :从 BASH4 开始,您现在可以使用
-i
来建议答案:
read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(But remember to use the "readline" option -e
to allow line editing with arrow keys) (但请记住使用“readline”选项
-e
以允许使用箭头键进行行编辑)
If you want a "yes / no" logic, you can do something like this:如果你想要一个“是/否”的逻辑,你可以这样做:
read -e -p "
List the content of your home dir ? [Y/n] " YN
[[ $YN == "y" || $YN == "Y" || $YN == "" ]] && ls -la ~/
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
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?"
...
Here's something I put together:这是我整理的一些东西:
#!/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
I'm a beginner, so take this with a grain of salt, but it seems to work.我是一个初学者,所以带着一粒盐,但它似乎工作。
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
[[ -t 0 ]] && read ...
=> Call command read
if TTY [[ -t 0 ]] && read ...
=> 调用命令read
if TTYread -n 1
=> Wait for one character read -n 1
=> 等待一个字符$'\e[1;32m ... \e[0m '
=> Print in green $'\e[1;32m ... \e[0m '
=> 以绿色打印[[ $do_xxxx =~ ^(y|Y|)$ ]]
=> bash regex [[ $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
The easiest way to achieve this with the least number of lines is as follows:以最少的行数实现此目的的最简单方法如下:
read -p "<Your Friendly Message here> : y/n/cancel" CONDITION;
if [ "$CONDITION" == "y" ]; then
# do something here!
fi
The if
is just an example: it is up to you how to handle this variable. if
只是一个例子:如何处理这个变量取决于你。
Use the read
command:使用
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
and then all of the other stuff you need然后是你需要的所有其他东西
This solution reads a single character and calls a function on a yes response.此解决方案读取单个字符并在是响应时调用函数。
read -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_something
fi
It is possible to handle a locale-aware "Yes / No choice" in a POSIX shell;可以在 POSIX shell 中处理区域设置感知的“是/否选择”; by using the entries of the
LC_MESSAGES
locale category, witch provides ready-made RegEx patterns to match an input, and strings for localized Yes No.通过使用
LC_MESSAGES
语言环境类别的条目,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
EDIT: As @Urhixidur mentioned in his comment :编辑:正如@Urhixidur在他的评论中提到的:
Unfortunately, POSIX only specifies the first two (yesexpr and noexpr).
不幸的是,POSIX 只指定了前两个(yesexpr 和 noexpr)。 On Ubuntu 16, yesstr and nostr are empty.
在 Ubuntu 16 上,yesstr 和 nostr 为空。
See: https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06见: https ://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06
LC_MESSAGES
LC_MESSAGES
The
yesstr
andnostr
locale keywords and theYESSTR
andNOSTR
langinfo items were formerly used to match user affirmative and negative responses.yesstr
和nostr
语言环境关键字以及YESSTR
和NOSTR
langinfo 项以前用于匹配用户的肯定和否定响应。 In POSIX.1-2008, theyesexpr
,noexpr
,YESEXPR
, andNOEXPR
extended regular expressions have replaced them.在 POSIX.1-2008 中,
yesexpr
、noexpr
、YESEXPR
和NOEXPR
扩展正则表达式已取代它们。 Applications should use the general locale-based messaging facilities to issue prompting messages which include sample desired responses.应用程序应该使用通用的基于语言环境的消息传递工具来发出提示消息,其中包括示例所需的响应。
Alternatively using locales the Bash way:或者使用 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
The answer is matched using locale environment's provided regexps.答案是使用语言环境提供的正则表达式匹配的。
To translate the remaining messages, use bash --dump-po-strings scriptname
to output the po strings for localization:要翻译剩余的消息,请使用
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 ""
To get a nice ncurses-like inputbox use the command dialog like this:要获得类似 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
The dialog package is installed by default at least with SUSE Linux.对话框包至少在 SUSE Linux 中默认安装。 Looks like:
好像:
In my case I needed to read from a downloaded script ie,就我而言,我需要从下载的脚本中读取,即,
curl -Ss https://example.com/installer.sh | sh
The line read -r yn </dev/tty
allowed it to read input in this case.在这种情况下,
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
# Yes
else
# No
fi
Here's a longer, but reusable and modular approach:这是一种更长但可重用且模块化的方法:
0
=yes and 1
=no0
= 是和1
= 否zsh
and bash
.zsh
和bash
。 Note that the N
is capitalsed.请注意,
N
是大写的。 Here enter is pressed, accepting the default:这里输入被按下,接受默认值:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?
Also note, that [y/N]?
另请注意,
[y/N]?
was automatically appended.被自动附加。 The default "no" is accepted, so nothing is echoed.
接受默认的“否”,因此不会回显任何内容。
Re-prompt until a valid response is given:重新提示直到给出有效响应:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *
Note that the Y
is capitalised:注意
Y
是大写的:
$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *
Above, I just pressed enter, so the command ran.上面,我只是按了回车,所以命令运行了。
y
or n
y
或n
$ 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
Here, 1
or false was returned.在这里,返回
1
或 false。 Note that with this lower-level function you'll need to provide your own [y/n]?
请注意,使用此较低级别的功能,您需要提供自己的
[y/n]?
prompt.迅速的。
# 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
}
You can use the default REPLY
on a read
, convert to lowercase and compare to a set of variables with an expression.您可以在
read
上使用默认REPLY
,转换为小写并使用表达式与一组变量进行比较。
The script also supports ja
/ si
/ oui
该脚本还支持
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
read -e -p "Enter your choice: " choice
The -e
option enables the user to edit the input using arrow keys. -e
选项使用户能够使用箭头键编辑输入。
If you want to use a suggestion as input:如果您想使用建议作为输入:
read -e -i "yes" -p "Enter your choice: " choice
-i
option prints a suggestive input. -i
选项打印提示性输入。
I noticed that no one posted an answer showing multi-line echo menu for such simple user input so here is my go at it:我注意到没有人针对如此简单的用户输入发布显示多行回显菜单的答案,所以这是我的尝试:
#!/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
This method was posted in the hopes that someone may find it useful and time-saving.发布此方法是希望有人会发现它有用且节省时间。
One-liner:单线:
read -p "Continue? [Enter] → Yes, [Ctrl]+[C] → No."
This assumes that "No" and "Cancel" have the same outcome, so no reason to treat them differently.这假设“否”和“取消”具有相同的结果,因此没有理由区别对待它们。
检查这个
read -p "Continue? (y/n): " confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] || exit 1
Multiple choice version:多选版本:
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
}
Example:例子:
$ 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
$
It will set REPLY
to y
(inside the script).它将
REPLY
设置为y
(在脚本内)。
Inspired by the answers of @Mark and @Myrddin I created this function for a universal prompt受@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
}
use it like this:像这样使用它:
unipromtp "Select an option: (a)-Do one (x)->Do two (f)->Do three : " "a x f" selection
echo "$selection"
I suggest you use dialog ...我建议你使用对话框...
Linux Apprentice: Improve Bash Shell Scripts Using Dialog
Linux 学徒:使用对话框改进 Bash Shell 脚本
The dialog command enables the use of window boxes in shell scripts to make their use more interactive.
dialog 命令允许在 shell 脚本中使用窗口框,以使它们的使用更具交互性。
it's simple and easy to use, there's also a gnome version called gdialog that takes the exact same parameters, but shows it GUI style on X.它简单易用,还有一个名为 gdialog 的 gnome 版本,它采用完全相同的参数,但在 X 上显示了 GUI 样式。
more generic would be:更通用的是:
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
}
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!'
One simple way to do this is with xargs -p
or gnu parallel --interactive
.一种简单的方法是使用
xargs -p
或 gnu parallel --interactive
。
I like the behavior of xargs a little better for this because it executes each command immediately after the prompt like other interactive unix commands, rather than collecting the yesses to run at the end.我更喜欢 xargs 的行为,因为它像其他交互式 unix 命令一样在提示符后立即执行每个命令,而不是收集 yesses 以在最后运行。 (You can Ctrl-C after you get through the ones you wanted.)
(你可以通过你想要的那些后按Ctrl-C。)
eg,例如,
echo *.xml | xargs -p -n 1 -J {} mv {} backup/
As a friend of a one line command I used the following:作为单行命令的朋友,我使用了以下命令:
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=;
Written longform, it works like this:书面长格式,它的工作原理是这样的:
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=;
I've used the case
statement a couple of times in such a scenario, using the case statment is a good way to go about it.在这种情况下,我已经多次使用
case
语句,使用 case 语句是一个很好的方法。 A while
loop, that ecapsulates the case
block, that utilizes a boolean condition can be implemented in order to hold even more control of the program, and fulfill many other requirements.可以实现使用布尔条件封装
case
块的while
循环,以便对程序进行更多控制,并满足许多其他要求。 After the all the conditions have been met, a break
can be used which will pass control back to the main part of the program.在满足所有条件后,可以使用
break
将控制权交还给程序的主要部分。 Also, to meet other conditions, of course conditional statements can be added to accompany the control structures: case
statement and possible while
loop.此外,为了满足其他条件,当然可以添加条件语句来伴随控制结构:
case
语句和可能的while
循环。
Example of using a case
statement to fulfill your request使用
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
#!/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
This is what I usually need in a script/function:这是我通常在脚本/函数中需要的:
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!"
The absolute most simple solution is this one-liner without clever tricks:绝对最简单的解决方案是这个没有巧妙技巧的单线:
read -p "press enter ..." y
It reminds of the classic DOS Hit any key to continue
, except that it waits for the Enter key, not just any key.它让人想起经典的 DOS
Hit any key to continue
,除了它等待 Enter 键,而不仅仅是任何键。
True, this does not offer you three options for Yes No Cancel, but it is useful where you accept control-C as No resp.诚然,这并没有为您提供 Yes No Cancel 的三个选项,但在您接受 control-C 作为 No resp 时它很有用。 Cancel in simple scripts like, eg:
在简单的脚本中取消,例如:
#!/bin/sh
echo Backup this project
read -p "press enter ..." y
rsync -tavz . /media/hard_to_remember_path/backup/projects/yourproject/
because you don't like to need to remember ugly commands and paths, but neither scripts that run too fast, without giving you a chance to stop before you decide it is not the script you intended to run.因为您不喜欢记住丑陋的命令和路径,但既不记住运行速度过快的脚本,也不给您机会在您确定它不是您打算运行的脚本之前停下来。
In response to others:回应别人:
You don't need to specify case in BASH4 just use the ',,' to make a var lowercase.您不需要在 BASH4 中指定大小写,只需使用 ',,' 将 var 设为小写即可。 Also I strongly dislike putting code inside of the read block, get the result and deal with it outside of the read block IMO.
此外,我非常不喜欢将代码放在读取块内,获取结果并在读取块 IMO 之外处理它。 Also include a 'q' for quit IMO.
还包括退出 IMO 的“q”。 Lastly why type 'yes' just use -n1 and have the press y.
最后,为什么键入“是”只需使用 -n1 并按 y。
Example: user can press y/n and also q to just quit.示例:用户可以按 y/n 也可以按 q 退出。
ans=''
while true; do
read -p "So is MikeQ the greatest or what (y/n/q) ?" -n1 ans
case ${ans,,} in
y|n|q) break;;
*) echo "Answer y for yes / n for no or q for quit.";;
esac
done
echo -e "\nAnswer = $ans"
if [[ "${ans,,}" == "q" ]] ; then
echo "OK Quitting, we will assume that he is"
exit 0
fi
if [[ "${ans,,}" == "y" ]] ; then
echo "MikeQ is the greatest!!"
else
echo "No? MikeQ is not the greatest?"
fi
Lots of good answers to this question, but from what I can see none of them are my ideal, which would:这个问题有很多很好的答案,但据我所知,它们都不是我的理想,它会:
Here's my version which does has those properties:这是我的版本,它确实具有这些属性:
read -n1 -p "Continue? (Y/n) " confirm
if ! echo $confirm | grep '^[Yy]\?$'; then
exit 1
fi
You can modify that conditional to only run on "yes" (just remove the !
in the if
statement) or add an else
if you want to run code on both branches.您可以将该条件修改为仅在“是”上运行(只需删除
if
语句中的!
),或者如果您想在两个分支上运行代码,则添加else
。
I've made this small script for yes/no questions: https://github.com/optimistiCli/getans我为是/否问题制作了这个小脚本: https ://github.com/optimistiCli/getans
Example:例子:
#!/bin/bash
if ! getans.sh 'Shall we proceed?' y ; then
echo "User said “NO”"
exit 1
fi
echo "User said “YES”"
# do something usefull
exit 0
Direct link: https://github.com/optimistiCli/getans/raw/main/getans.sh直接链接: https ://github.com/optimistiCli/getans/raw/main/getans.sh
A one-liner python
alternative using PyInquirer使用PyInquirer的单行
python
替代方案
python3 -c 'import PyInquirer; print(PyInquirer.prompt([{"type":"confirm", "message":"Do you want to continue?", "name":"r"}]).get("r"))'
which supports yes/no/cancel (intr, CTRL+C).它支持是/否/取消(intr,CTRL+C)。
You can write a function to test:你可以写一个函数来测试:
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]"; then
echo "rebooting..."
sleep 5
reboot
fi
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.