Linux script yes no

Asking a Yes/No Question from a Bash Script

In order to avoid this common mistake I often have my shell scripts prompt me for a yes or no answer before they proceed. The function described here is for doing that: asking a question and validating the answer.

The function is pretty simple it accepts a couple of options and the remainder of the arguments are presumed to be the question text. It prompts the user for an answer and validates that the answer is one of «yes», «y», «no», or «n». The answer is converted to lower case so any combination of case is accepted.

The available options are --timeout N which causes the prompt to timeout after N seconds, and --default ANS which provides a default answer for prompts that timeout. It also allows the user to hit ENTER and accept the default answer. The function code follows:

#!/bin/bash.sh # ##################################################################### # Print warning message. function warning()  echo "$*" >&2 > ##################################################################### # Print error message and exit. function error()  echo "$*" >&2 exit 1 > ##################################################################### # Ask yesno question. # # Usage: yesno OPTIONS QUESTION # # Options: # --timeout N Timeout if no input seen in N seconds. # --default ANS Use ANS as the default answer on timeout or # if an empty answer is provided. # # Exit status is the answer. function yesno()  local ans local ok=0 local timeout=0 local default local t while [[ "$1" ]] do case "$1" in --default) shift default=$1 if [[ ! "$default" ]]; then error "Missing default value"; fi t=$(tr '[:upper:]' '[:lower:]' $default) if [[ "$t" != 'y' && "$t" != 'yes' && "$t" != 'n' && "$t" != 'no' ]]; then error "Illegal default answer: $default" fi default=$t shift ;; --timeout) shift timeout=$1 if [[ ! "$timeout" ]]; then error "Missing timeout value"; fi if [[ ! "$timeout" =~ ^[0-9][0-9]*$ ]]; then error "Illegal timeout value: $timeout"; fi shift ;; -*) error "Unrecognized option: $1" ;; *) break ;; esac done if [[ $timeout -ne 0 && ! "$default" ]]; then error "Non-zero timeout requires a default answer" fi if [[ ! "$*" ]]; then error "Missing question"; fi while [[ $ok -eq 0 ]] do if [[ $timeout -ne 0 ]]; then if ! read -t $timeout -p "$*" ans; then ans=$default else # Turn off timeout if answer entered. timeout=0 if [[ ! "$ans" ]]; then ans=$default; fi fi else read -p "$*" ans if [[ ! "$ans" ]]; then ans=$default else ans=$(tr '[:upper:]' '[:lower:]' $ans) fi fi if [[ "$ans" == 'y' || "$ans" == 'yes' || "$ans" == 'n' || "$ans" == 'no' ]]; then ok=1 fi if [[ $ok -eq 0 ]]; then warning "Valid answers are: yes y no n"; fi done [[ "$ans" = "y" || "$ans" == "yes" ]] > if [[ $(basename "$0" .sh) == 'yesno' ]]; then if yesno "Test bad timeout value? "; then yesno --timeout none "Hello? " fi if yesno "Test timeout without default value? "; then yesno --timeout 10 "Hello? " fi if yesno "Test bad default value? "; then yesno --default none "Hello? " fi if yesno "Yes or no? "; then echo "You answered yes" else echo "You answered no" fi if yesno --default yes "Yes or no (default yes) ? "; then echo "You answered yes" else echo "You answered no" fi if yesno --default no "Yes or no (default no) ? "; then echo "You answered yes" else echo "You answered no" fi if yesno --timeout 5 --default no "Yes or no (timeout 5, default no) ? "; then echo "You answered yes" else echo "You answered no" fi if yesno --timeout 5 --default yes "Yes or no (timeout 5, default yes) ? "; then echo "You answered yes" else echo "You answered no" fi fi # vim: tabstop=4: shiftwidth=4: noexpandtab: # kate: tab-width 4; indent-width 4; replace-tabs false; 

The code starts with a couple of functions which print warning and error messages. The main function checks the arguments then loops until it receives a valid answer. Note that if a timeout was specified and any answer (valid or invalid) is entered the timeout is turned off. The last line of the function tests the answer to see if it’s value is «yes» or «y», thereby setting the exit status of the function.

The code at the end of the file is only executed if you invoke the file directly rather than sourceing it into your shell script. Output from a direct run follows:

$ sh yesno.sh Test bad timeout value? n Test timeout without default value? n Test bad default value? n Yes or no? yep Valid answers are: yes y no n Yes or no? yes You answered yes Yes or no (default yes) ? You answered yes Yes or no (default no) ? You answered no Yes or no (timeout 5, default no) ? You answered no Yes or no (timeout 5, default yes) ? You answered yes

Notice the last couple of lines, no answer was provided so the default was used after the timeout. That’s why the response text appears on the same line as the question.

Mitch Frazier is an embedded systems programmer at Emerson Electric Co. Mitch has been a contributor to and a friend of Linux Journal since the early 2000s.

Источник

How to prompt for yes or no in bash? [duplicate]

How do I ask a yes/no type question in Bash? I ask the question. echo «Do you like pie?» And receive the answer. read pie How do I do something if the answer is yes , or starts with y (so yes and yeah, etc, will work too).

For zsh users, the -q option is available. Read only one character from the terminal and set name to ‘y’ if this character was ‘y’ or ‘Y’ and to ‘n’ otherwise. With this flag set the return status is zero only if the character was ‘y’ or ‘Y’. Note that this always reads from the terminal, even if used with the -p or -u or -z flags or with redirected input. This option may also be used within zle widgets.

@UlysseBN zsh never ceases to amaze me! I don’t remember what this original question was for, but I’m going to keep that in mind for when I have control of the shell executing my script — thank you!

6 Answers 6

I like to use the following function:

So in your script you can use like this:

yes_or_no "$message" && do_something 

In case the user presses any key other than [yYnN] it will repeat the message.

read -p «$@ [y/n]: » is incorrect, you need to use $* or the read will explode if the function is called with more than one argument. Also, technically this should use yes_or_not «$@» but for this that only matters if you use yes_or_not ‘foo bar’ and then the user doesn’t input yes or no (the inner spaces will then get lost).

I added a question mark after the $* . This also works great with an if block: if yes_or_no «Do next task»; then ;;;; fi constructs

read -e -p "Do you like pie? " choice [[ "$choice" == [Yy]* ]] && echo "doing something" || echo "that was a no" 

Pattern starting with Y or y will be taken as yes .

I like Jahid’s oneliner. Here is a slight simplification of it:

[[ "$(read -e -p 'Continue? [y/N]> '; echo $REPLY)" == [Yy]* ]] 
$ [[ "$(read -e -p 'Continue? [y/N]> '; echo $REPLY)" == [Yy]* ]] && echo Continuing || echo Stopping Continue? [y/N]> yes Continuing $ for test_string in y Y yes YES no ''; do echo "Test String: '$test_string'"; echo $test_string | [[ "$(read -e -p 'Continue? [y/N]>'; echo $REPLY)" == [Yy]* ]] && echo Continuing || echo Stopping; done Test String: 'y' Continuing Test String: 'Y' Continuing Test String: 'yes' Continuing Test String: 'YES' Continuing Test String: 'no' Stopping Test String: '' Stopping 

In response to a comment, I’m going to add an adaptation to make this work in zsh .

I would never write a shell script in zsh even though it is now my primary interactive shell. I still write all scripts in bash or sh . However, since you sometimes need to script modifications to your interactive shell (ex: source ~/dev/set_env ), you might want to include prompting.

#! /usr/bin/env zsh [[ "$(echo -n 'Continue? [y/N]> ' >&2; read; echo $REPLY)" == [Yy]* ]] \ && echo Continuing \ || echo Stopping 

Источник

Is there any default function/utility to prompt the user for yes/no in a Bash script?

Ah, there is something built-in: zenity is a graphical dialog program:

if zenity --question --text="Is this OK?" --ok-label=Yes --cancel-label=No then # user clicked "Yes" else # user clicked "No" fi 

In addition to zenity , you can use one of:

if dialog --yesno "Is this OK?" 0 0; then . if whiptail --yesno "Is this OK?" 0 0; then . 

That looks fine to me. I would just make it a bit less «do or die»:

That way you can do something like:

if check_yes_no "Do important stuff? [Y/n] "; then # do the important stuff else # do something else fi # continue with the rest of your script 

With @muru’s select suggestion, the function can be very terse:

check_yes_no () < echo "$1" local ans PS3=">" select ans in Yes No; do [[ $ans == Yes ]] && return 0 [[ $ans == No ]] && return 1 done > 

As a conclusion I wrote this script:

#!/bin/bash usage() < echo "Show yes/no dialog, returns 0 or 1 depending on user answer" echo "Usage: $0 [OPTIONS] -x force to use GUI dialog -m message that user will see" 1>&2 exit 1; > while getopts m:xh opts; do case $ in x) FORCE_GUI=true; ;; m) MSG=$ ;; h) usage ;; esac done if [ -z "$MSG" ];then usage fi # Yes/no dialog. # If the user enters n/N, return 1. while true; do if [ -z $FORCE_GUI ]; then read -p "$MSG" yn case "$yn" in [Yy] ) exit 0;; [Nn] ) echo "Aborting. " >&1 exit 1;; * ) echo "Please answer y or n for yes or no.";; esac else if [ -z $DISPLAY ]; then echo "DISPLAY variable is not set" >&1 ; exit 1; fi if zenity --question --text="$MSG" --ok-label=Yes --cancel-label=No; then exit 0 else echo "Aborting. " >&1 exit 1 fi fi done; 

Latest version of script can be found here. Fill free to change/edit

 read -p ". Are You sure [y/N]? " -n 1 if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo ". Canceled by user." exit 1 fi 
 read -p ". Are You sure [Y/n]" -n 1 if [[ $REPLY =~ ^[Nn]$ ]]; then echo ". Canceled by user." exit 1 fi 
 read -p 'Are you sure you want to continue? (y/n) ' -n 1 confirmation echo '' if [[ $confirmation != 'y' && $confirmation != 'Y' ]]; then exit 3 fi # Code to execute if user wants to continue here. 

You must log in to answer this question.

Linked

Hot Network Questions

Subscribe to RSS

To subscribe to this RSS feed, copy and paste this URL into your RSS reader.

Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.13.43530

Ubuntu and the circle of friends logo are trade marks of Canonical Limited and are used under licence.

By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.

Источник

How do I prompt a user for confirmation in bash script? [duplicate]

I want to put a quick «are you sure?» prompt for confirmation at the top of a potentially dangerous bash script, what’s the easiest/best way to do this?

10 Answers 10

read -p "Are you sure? " -n 1 -r echo # (optional) move to a new line if [[ $REPLY =~ ^[Yy]$ ]] then # do dangerous stuff fi 

I incorporated levislevis85‘s suggestion (thanks!) and added the -n option to read to accept one character without the need to press Enter . You can use one or both of these.

Also, the negated form might look like this:

read -p "Are you sure? " -n 1 -r echo # (optional) move to a new line if [[ ! $REPLY =~ ^[Yy]$ ]] then [[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 # handle exits from shell or function but don't exit interactive shell fi 

However, as pointed out by Erich, under some circumstances such as a syntax error caused by the script being run in the wrong shell, the negated form could allow the script to continue to the «dangerous stuff». The failure mode should favor the safest outcome so only the first, non-negated if should be used.

Explanation:

The read command outputs the prompt ( -p «prompt» ) then accepts one character ( -n 1 ) and accepts backslashes literally ( -r ) (otherwise read would see the backslash as an escape and wait for a second character). The default variable for read to store the result in is $REPLY if you don’t supply a name like this: read -p «my prompt» -n 1 -r my_var

The if statement uses a regular expression to check if the character in $REPLY matches ( =~ ) an upper or lower case «Y». The regular expression used here says «a string starting ( ^ ) and consisting solely of one of a list of characters in a bracket expression ( [Yy] ) and ending ( $ )». The anchors ( ^ and $ ) prevent matching longer strings. In this case they help reinforce the one-character limit set in the read command.

The negated form uses the logical «not» operator ( ! ) to match ( =~ ) any character that is not «Y» or «y». An alternative way to express this is less readable and doesn’t as clearly express the intent in my opinion in this instance. However, this is what it would look like: if [[ $REPLY =~ ^[^Yy]$ ]]

Источник

Читайте также:  Linux professional institute linux essentials
Оцените статью
Adblock
detector