标签云

微信群

扫码加入我们

WeChat QR Code

I want to pause input in a shell script, and prompt the user for choices. The standard 'Yes, No, or Cancel' type question. How do I accomplish this in a typical bash prompt?


Just as a note: convention for prompts are such that if you present a [yn] option, the one that is capitalized is default, i.e. [Yn] defaults to "yes", and [yN] defaults to "no". See ux.stackexchange.com/a/40445/43532

2019年10月21日39分33秒

Using Bash in OS X Leopard, I changed exit to break to keep from closing the tab when I selected 'no'.

2019年10月20日39分33秒

How does this work with options longer than Yes or No? In the case clause, do you write something like: Install program and do nothing afterwards ) make install; break;

2019年10月20日39分33秒

why is there a break in the select if there is no loop?

2019年10月20日39分33秒

akostadinov I really should read my edit history more. You are correct, I'm wrong, and I introduced a bug following Jayan's advice, hah. The bug was later fixed, but the edits were so far apart I didn't even remember changing it.

2019年10月20日39分33秒

FWIW, I used this example to create a script that I intended to trigger via a remote SSH session. My SSH command looked like this: ssh my-server 'path/to/myscript.sh'. When executing this way, the prompt text for the read -p command does not show up. However, output from the echo command does. So for me, the better solution was to use echo -n "Do something? " followed by read yn.

2019年10月21日39分33秒

Note that stty provides the -g option for use: old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty".This restores the setting exactly as they were found, which may or may not be the same as stty -sane.

2019年10月20日39分33秒

read answer will interpret backslashes before spaces and line feeds, and otherwise strip them which is rarely intended. Use read -r answer instead as per SC2162.

2019年10月20日39分33秒

vlfig A agree: expecting backslashes from user input in a Yes/No/Cancel dialog is rarely intended... I think It's the main reason because I've not used -r option.

2019年10月20日39分33秒

The "Using readline's history" method is so terribly inappropriate for the OP's question. I'm glad you included it anyway. I have dozens of much more complicated scripts that I intend to update with that pattern!

2019年10月20日39分33秒

You can use case for POSIX as well as bash (use a wildcard condition rather than a bash substring: case $answer in; [Yy]* ) echo Yes ;;), but I prefer using a conditional statement instead, favoring [ "$answer" != "${answer#[Yy]}" ] over your echo "$answer" | grep -iq ^y. It's more portable (some non-GNU greps don't implement -q correctly) and it doesn't have the system call.${answer#[Yy]} uses parameter expansion to remove Y or y from the beginning of $answer, causing an inequality when either is present. This works in any POSIX shell (dash, ksh, bash, zsh, busybox, etc).

2019年10月20日39分33秒

I disagree, because it only implements a portion of the functionality of the 'Yes, No, Cancel' dialog in DOS. The part it fails to implement is input checking... looping until a valid answer is received.

2019年10月20日39分33秒

(The original question title was "How do I prompt for input in a Linux shell script?")

2019年10月20日39分33秒

But the original question description is unchanged, and always asked for a response to a Yes/No/Cancel prompt. The title has been updated to be clearer than my original one, but the question description was always clear (in my opinion).

2019年10月20日39分33秒

It should be noted that FILEPATH is the variable name you have chosen, and is set with the answer to the command prompt. So if you were to then run vlc "$FILEPATH", for example, vlc would open that file.

2019年10月20日39分33秒

What's the benefit of -e in the second example (simple yes/no)?

2019年10月21日39分33秒

Any reason to use -e -p instead of -ep?

2019年10月20日39分33秒

Without the -e flag/option, you might (depending on the implementation) not be able to type "y", and then change your mind and replace it with a "n" (or anything else for that matter) ;When documenting a command, listing the options separately is better for readability/clarity, among other reasons.

2019年10月20日39分33秒

+1 Geniously simple solution. Only thing: This will prompt and promt and prompt... until you add an exit inside :)

2019年10月20日39分33秒

(kaiser: To break from it, just enter the EOT: Ctrl-D. But of course, real code using it will need a break or an exit in the body.)

2019年10月20日39分33秒

This will not allow you to enter y or n, though.You choose by entering 1 2 or 3.

2019年10月20日39分33秒

exit will exit the script all together, break will only exit the loop you are in (if you are on a while or case loop)

2019年10月21日39分33秒

If you change case $yn in to case ${yn:-$2} in then you can use the second argument as the default value, Y or N.

2019年10月21日39分33秒

Put four spaces in the beginning of each line to preserve the formatting of code.

2019年10月20日39分33秒

Why we providing 'y' and 'n' as parameters to inquire() if the case switches are hardcoded? That's just asking for misuse. They are fixed parameters, not changable, so the echo on line 2 should read:echo -n "$1 [Y/N]? "They can't be changed, so they shouldn't be supplied.

2019年10月20日39分33秒

MyrddinEmrys Could you please elaborate your comment? Or post a link to an article or a couple of keywords so I could do research on my own.

2019年10月20日39分33秒

MateuszPiotrowski The answer has been edited and improved since I made my comment. You can click the 'edited Dec 23' link above to view all the past versions of this answer. Back in 2008, the code was quite different.

2019年10月20日39分33秒

why the 'echo' ?

2019年10月20日39分33秒

Jav the echo prints a newline after your response. Without it, the next thing to be printed would appear immediately after your response on the same line. Try removing the echo to see for yourself.

2019年10月20日39分33秒

(note: options are specific to bash (don't work in zsh)

2019年10月21日39分33秒

yap, -e -i don't work in sh (Bourne shell), but the question is tagged bash specifically..

2019年10月20日39分33秒

I know, :) I was just adding this information.

2019年10月20日39分33秒

An important part of this is input validation. I think adapting my first example to accept tty input as you did would have done as well for you, and also gotten looping on bad input (imagine a few characters in the buffer; your method would force the user to always choose no).

2019年10月20日39分33秒

xyz thanks for sharing 👍 this is exactly what I was looking for.

2019年10月20日39分33秒

When I tested this script, instead of the outut above I got, Show dangerous command [y/N]?[y/n]? and Show dangerous command [Y/n]?[y/n]?

2019年10月20日39分33秒

Thanks IliasKarim, I fixed that just now.

2019年10月20日39分33秒

For the casual reader, have look to a snippet using the dialog command here: stackoverflow.com/a/22893526/363573

2019年10月20日39分33秒

Not bad, but xargs --interactive is limited to yes or no. As long as that's all you need that can be enough, but my original question gave an example with three possible results. I really like that it is streamable though; many common scenarios would benefit from its ability to be piped.

2019年10月20日39分33秒

I see. My thinking was that "cancel" meant to simply stop all further execution, which this supports via Ctrl-C, but if you need to do something more complex on cancel (or on no) this won't suffice.

2019年10月20日39分33秒

Can you clarify the use of the prompt variable? Looks to me like it's wiped after the one liner, so how do you use the line to DO anything?

2019年10月20日39分33秒

prompt is wiped after the while loop. Because I want the prompt variable to be initialized afterwards (since I am using the statement more often). Having this line in a shell-script will only proceed if y|Y is typed and exit if n|N is typed or repeat asking for input for everything else.

2019年10月20日39分33秒

Better clear it before the loop

2019年10月21日39分33秒

This seems complex and fragile. How about just yn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure

2019年10月20日39分33秒

The above codeshould work without the evals.

2019年10月20日39分33秒

Upvoted for the lowercase shortcut, I like that.

2019年10月20日39分33秒

I love the addition of a language agnostic option. Well done.

2019年10月20日39分33秒