问题
I am writing an interactive shell script that needs to run on as many systems as possible. Is there an alternative way to implement the following that is compatible with a standard POSIX system?
#! /bin/bash
echo -n "Do you wish to continue? (Y/n) 5 seconds to respond... "
read -n 1 -t 5 answer # accepts a single character, 5 second timeout.
if [ "$answer" = "n" ] || [ "$answer" = "N" ] ; then
echo -e "\nExiting..."
exit
fi
echo -e "\nContinuing with script..."
# More code
The timeout on read
is most important to me (read -t 5
). The one character limit for read is desirable but not essential (read -n 1
).
Ideally, the script would work on POSIX systems and also within bash without having to enable a special POSIX compatibility mode.
回答1:
Adapting the stty settings from Mr Dickey's answer, the following seems to work and continues with the script if anything other than 'n' or 'N' is pressed.
As far as I can tell, all of the stty settings are posix.
#!/bin/sh
read_char() {
old=$(stty -g)
stty raw -echo min 0 time 50
eval "$1=\$(dd bs=1 count=1 2>/dev/null)"
stty $old
}
printf "Do you wish to continue? (Y/n) 5 seconds to respond..."
read_char answer
# answer=$(getch)
# answer=$(getche)
if [ "$answer" = "n" ] || [ "$answer" = "N" ] ; then
printf "\nExiting...\n"
exit
fi
printf "\nContinuing with script...\n"
Alternatives to "read_char":
This avoids using eval (can be unsafe)
getch() {
old=$(stty -g)
stty raw -echo min 0 time 50
printf '%s' $(dd bs=1 count=1 2>/dev/null)
stty $old
}
This avoids eval and prints the pressed key
getche() {
old=$(stty -g)
stty raw min 0 time 50
printf '%s' $(dd bs=1 count=1 2>/dev/null)
stty $old
}
回答2:
The stty program provides the means to do this. xterm has several scripts (in its source's "vttests" subdirectory) which save, modify and restore terminal settings to allow it to read the terminal's response to escape sequences. Here is a part of dynamic2.sh
(the beginning sets up printf
or echo
, to address some old systems with the $CMD
variable):
echo "reading current color settings"
exec </dev/tty
old=`stty -g`
stty raw -echo min 0 time 5
original=
for N in $FULL
do
$CMD $OPT "${ESC}]$N;?^G${SUF}" > /dev/tty
read reply
eval original$N='${reply}${SUF}'
original=${original}${reply}${SUF}
done
stty $old
if ( trap "echo exit" EXIT 2>/dev/null ) >/dev/null
then
trap '$CMD $OPT "$original" >/dev/tty; exit' EXIT HUP INT TRAP TERM
else
trap '$CMD $OPT "$original" >/dev/tty; exit' 0 1 2 5 15
fi
来源:https://stackoverflow.com/questions/32213758/posix-alternative-to-bash-read-with-timeout-and-character-limit