How to Read with Timeout Without Making Bash Consider It an Error?
I Have a Read_User_Input. Sh Script: #! /Bin/Bash # Set -E Prompt="Bla? [Y/N] " While True; Do Read -P "$Prompt" -N 1 -S -T 3 Reply Case $Reply in ""|Y|Y) Echo...
I have a read_user_input.sh script:
#!/bin/bash
# set -e
prompt="bla? [Y/n] "
while true; do
read -p "$prompt" -n 1 -s -t 3 reply
case $reply in
""|Y|y) echo "bla!!!"; break;;
N|n) echo "no bla :( you suck"; break;;
*) ;;
esac
done
Works as I expected - i.e.
- User inputs "Y" -> bla
- User inputs "y" -> bla
- User hits Enter -> bla
- Timeout -> bla
However, when adding set -e - the read ends with error > 128.
From read --help:
Exit Status:The return code is zero, unless end-of-file is encountered, read times out (in which case it's greater than 128), a variable assignment error occurs, or an invalid file descriptor is supplied as the argument to -u.
What would be the best way to overcome this?
- adding
|| trueseems not right, as it would hide any real errors. - I also don't want to remove the
set -e. - One other thing I thought about was handling it in
trapbut that seems like an overkill
3 Answers
Instead of adding || true, set the $reply to y if there was a timeout:
read -p "$prompt" -n 1 -s -t 3 reply || {
err=$?
if (( $err > 128 )) ; then
reply=y
else
exit $err
fi
}
Here is a hack where is used command substitution which forks a subshell where -e is not enabled.
#!/bin/bash
set -e
prompt="bla? [Y/n] "
while true; do
case $(read -p "$prompt" -n 1 -s -t 3 reply; echo $reply) in
""|Y|y) echo "bla!!!"; break;;
N|n) echo "no bla :( you suck"; break;;
*) ;;
esac
done
Using @choroba answer, I changed my switch case into:
#!/bin/bash
set -e
prompt="bla? [Y/n] "
while true; do
read -p "$prompt" -n 1 -s -t 3 reply || (( $? > 128 ))
case $reply in
""|Y|y) echo "bla!!!"; break;;
N|n) echo "no bla :( you suck"; break;;
*) ;;
esac
done