Press space to continue

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.

Asked By: rubo77

||
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
Answered By: mikeserv

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.

Answered By: AleksanderKseniya

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

Example

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...
$ 

References

Answered By: slm

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"
Answered By: rubo77

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.

Answered By: gcb

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
Answered By: Robin A. Meade

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!

Answered By: Tom Hale

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.

Answered By: adazem009

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.

Answered By: Paul
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.