No pressing enter required
Here's a longer, but reusable and modular approach:
- Returns
0=yes and 1=no - No pressing enter required - just a single character
- Can press enter to accept the default choice
- Can disable default choice to force a selection
- Works for both
zsh and bash.
Defaulting to "no" when pressing enter
Note that the N is capitalsed. Here enter is pressed, accepting the default:
$ confirm "Show dangerous command" && echo "rm *" Show dangerous command [y/N]?
Also note, that [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 *
Defaulting to "yes" when pressing enter
Note that the Y is capitalised:
$ confirm_yes "Show dangerous command" && echo "rm *" Show dangerous command [Y/n]? rm *
Above, I just pressed enter, so the command ran.
No default on enter - require y or n
$ get_yes_keypress "Here you cannot press enter. Do you like this" 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. Note no capitalisation in [y/n]?
Code
# 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 }
info bash: "For almost every purpose, shell functions are preferred over aliases."ls -lorrm -i?alias rm='rm -i'. One day, when you need it most, the alias won't be there andboom!something important will be lost.rm -i, then you cannot count on having a shell script as well. So do you always typerm -ievery time?rmand expecting the-ibehavior, then one day the alias is not there (for some reason it gets unset or not set or you're on a different system) and you typermand it goes ahead immediately deleting stuff without confirmation. Oops! However, if you did an alias likealias askrm='rm -i'then you'd be OK, since you'd get a "command not found" error.