How do I stop a bash script until a user has pressed Space?
I would like to have the question in my script
Press space to continue or CTRL+C to exit
and then the script should stop and wait until Space is pressed.
How do I stop a bash script until a user has pressed Space?
I would like to have the question in my script
Press space to continue or CTRL+C to exit
and then the script should stop and wait until Space is pressed.
You can use read
:
read -n1 -s -r -p $'Press space to continue...\n' key
if [ "$key" = ' ' ]; then
# Space pressed, do something
# echo [$key] is empty when SPACE is pressed # uncomment to trace
else
# Anything else pressed, do whatever else.
# echo [$key] not empty
fi
Replace ' '
for space at above with ''
for Enter key, $'\t'
for Tab key.
read -n1 -rsp $'Press any key to continue or Ctrl+C to exit...\n'
– rubo77
Jun 22 '14 at 09:24
else
block always runs, even when the spacebar is pressed.
– robert
Dec 22 '15 at 06:56
bash
. It works if you use read _
instead, if you have some other shell than bash
.
– Niklas Rosencrantz
May 02 '16 at 09:48
''
for an empty string. No space inside. I guess, it also fits, if you enter ENTER or TAB
– rubo77
Jan 10 '17 at 07:01
key
to empty string instead of a string with a space.
– Steven Lu
Feb 08 '18 at 22:09
$key
will be empty. It would have been better to do IFS= read -rn1
here and test again ' '
. See also Understanding "IFS= read -r line"
– Stéphane Chazelas
May 23 '18 at 22:13
IFS
as you describe) would ALSO respond the same if a tab or enter key are pressed...
– Steven Lu
May 23 '18 at 22:16
pipeline | script.sh
See this answer for a solution.
– Tom Hale
Jun 28 '18 at 05:25
The method discussed in this SO Q&A is likely the best candidate for an alternative to the pause
behavior that you're accustom to on Windows when doing BAT files.
$ read -rsp $'Press any key to continue...\n' -n1 key
Here I am running the above and then simply pressing any key, in this case the D key.
$ read -rsp $'Press any key to continue...\n' -n1 key
Press any key to continue...
$
echo -e "..."
lines. It's much more compact in those situations.
– slm
Jun 05 '14 at 07:58
You could create a pause
function for it to use everywhere in your script like:
#!/bin/bash
pause(){
while read -r -t 0.001; do :; done # dump the buffer
read -n1 -rsp $'Press any key to continue or Ctrl+C to exit...\n'
}
echo "try to press any key before the pause, it won't work..."
sleep 5
pause
echo "done"
hold=' '
printf "Press 'SPACE' to continue or 'CTRL+C' to exit : "
tty_state=$(stty -g)
stty -icanon
until [ -z "${hold#$in}" ] ; do
in=$(dd bs=1 count=1 </dev/tty 2>/dev/null)
done
stty "$tty_state"
This now prints a prompt without a trailing newline, handles CTRL+C
reliably, invokes stty
only as often as necessary, and restores the controlling tty to exactly the state in which stty
found it. Look into man stty
for information on how to explicitly control echoes, control characters and all.
You might also do this:
printf "Press any key to continue or 'CTRL+C' to exit : "
(tty_state=$(stty -g)
stty -icanon
LC_ALL=C dd bs=1 count=1 >/dev/null 2>&1
stty "$tty_state"
) </dev/tty
You could do it with ENTER
, no [
tests ]
and no stty
like:
sed -n q </dev/tty
/bin/sh
(e.g. on FreeBSD) too, not only with bash.
– zezollo
Jun 10 '20 at 15:24
Here's a way that works in both bash
and zsh
, and ensures I/O to the terminal:
# Prompt for a keypress to continue. Customise prompt with $*
function pause {
>/dev/tty printf '%s' "${*:-Press any key to continue... }"
[[ $ZSH_VERSION ]] && read -krs # Use -u0 to read from STDIN
[[ $BASH_VERSION ]] && </dev/tty read -rsn1
printf '\n'
}
export_function pause
Put it in your .{ba,z}shrc
for Great Justice!
Here's a simple solution from Press SPACE to continue (not ENTER)
read -r -s -d ' '
This will wait until you press the space bar. Yes, only the space bar, it wouldn't break if you pressed enter.
Settings IFS
to empty string suppresses read's default behavior of trimming white space.
try_this() {
echo -n "Press SPACE to continue or Ctrl+C to exit ... "
while true; do
# Set IFS to empty string so that read doesn't trim
# See http://mywiki.wooledge.org/BashFAQ/001#Trimming
IFS= read -n1 -r key
[[ $key == ' ' ]] && break
done
echo
echo "Continuing ..."
}
try_this
UPDATE 2018-05-23: We can simplify this by using the REPLY variable, which is not subject to word-splitting:
try_this() {
echo -n "Press SPACE to continue or Ctrl+C to exit ... "
while true; do
read -n1 -r
[[ $REPLY == ' ' ]] && break
done
echo
echo "Continuing ..."
}
try_this
lazy one liner:
echo "Press any key to continue or Ctrl+C to cancel"
read && do_something.sh
the disadvantage is that you lose control when the user press ctrl+c. The script will always exit with code 130 in that case.
Many wonderful answers using read -rn1
and that will work beautifully UNTIL you press an arrow key, or a function key, or any other key which lacks an ASCII representation and is translated by the terminal into an escape sequence of multiple characters to read. When that happens, you will have garbage characters waiting in the input buffer which will appear in the next read
.
Don't forget to clear the buffer before and after...
while read -r -t 0.001; do :; done # dump the buffer
read -r -n1 -p "Press any key to continue..." # wait
read -r -t 0.001 # dump the rest of any escape sequence
The -t is a timeout specification. The 0.001 is a 1/1000 of one second. Not long enough to notice the pause if no data is available, but the timeout is long enough to extract information from a waiting buffer.
The while loop clears the input buffer before waiting for a keystroke. This while loop prevents the user from being able to hit 5 keys to bypass the next 5 "Press any key to continue" notices. Instead, the user must wait until the notice appears before pressing a key will actually continue.
The last read clears any other keys currently waiting to be read. These keys would be the remainder of an escape sequence made by the one keypress.
Translating the escape sequences of varying lengths into a description of the actual keypress is certainly possible, but there is a standard, and you can test for the actual sequence.
while read -r -t 0.001; do :; done # dump the buffer
read -r -n1 -p "Press any key to continue..." # wait
read -r -t 0.001 zRest # read the entire escape sequence
RESULT+="$zRest" # create the actual keypress
This appends the remaining buffer onto the result of the read
whose keypress may create a multi-character escape sequence. It will work well until someone presses multiple keys at the same time. But if that happens, it is probably better to reject the mess as an unknown keypress anyway.