Short Answer:
Add a -s
option on the first read command and a -ei
option on the second read command:
read -s -N 1 -t 10 -p "What is your name? > " a
[ "$a" != "" ] && read -ei "$a" b && echo "Your name is $b" || echo "(timeout)"
Or with better handling of empty input:
read -s -N 1 -t 10 -p "What is your name? > " a || echo "(timeout)" \
&& [ -n "$a" ] && read -ei "$a" b || echo \
&& echo "Your name is \"$b\""
Elaborate Answer:
With the help of @chepner's answer (thanks for the -ei
option!) and a comment of @paul-hodges, which has lead me to an article promoting the -s
read option, I was able to create a working solution very similar to my original 2-liner:
read -N 1 -t 10 -s -p "What is your name? > " a
[ "$a" != "" ] && read -ei "$a" b && echo "Your name is $b" || echo "(timeout)"
Some of you might like a more elaborate version of the same functionality:
if read -N 1 -t 10 -s -p "What is your name? " FIRST_CHARACTER; then
read -ei "$FIRST_CHARACTER" FULL_NAME
echo "Your name is $FULL_NAME"
else
echo "(timeout)"
fi
Explanation:
- the
-s
option in the first read command will make sure the FIRST_CHARACTER is not printed out while typing.
- the
-N 1
or -n1
option will make sure that only the first character is read into the FIRST_CHARACTER variable
- the
-ei
option will read $FIRST_CHARACTER
into the FULL_NAME before the user continues to write the characters 2 to n.
- the user is able to reconsider his answer and he can remove the whole input including the first character with the backspace.
I have testet it, and the combination of those options seems to do the trick.
Resolving a Caveat with empty input
However, there is still a small caveat: if the user just types <enter>
: the second read command will wait for an input until the user is pressing <enter>
a second time. This can be fixed like follows:
if read -N 1 -t 10 -s -p "What is your name? " FIRST_CHARACTER; then
if [ -n "$FIRST_CHARACTER" ]; then
read -ei "$FIRST_CHARACTER" FULL_NAME
else
echo
fi
echo "Your name is \"$FULL_NAME\""
else
echo "(timeout)"
fi
In the style of the two-liner, this will get us a three-liner as follows:
read -N 1 -t 10 -s -p "What is your name? > " a || echo "(timeout)" \
&& [ -n "$a" ] && read -ei "$a" b || echo \
&& echo "Your name is \"$b\""
Test
The code of both versions (the nested if version and the three-liner) will behave as follows:
- If the user does not do anything for 10 sec, the output will yield
What is your name? (timeout)
- If the user writes
Oliver<enter>
the output will be
What is your name? Oliver
Your name is "Oliver"
- if the user starts to write "Oliver", then considers, that he want to be called "Michael", he can completely remove the "Oliver" with the backspace key and replace it accordingly. The output will be:
What is your name? Oliver
after entering the name "Oliver". Then, after pressing the backspace key 6 or more times:
What is your name?
And after entering Michael<enter>
:
What is your name? Michael
Your name is "Michael"
Hope that helps.