75

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.

58

You can use read:

read -n1 -r -p "Press space to continue..." 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
  • 12
    You should add -s to not to print the pressed character out on the terminal. And add a linebreak at the end, or the output will continue directly in the same line like the question. Best would be: read -n1 -rsp $'Press any key to continue or Ctrl+C to exit...\n' – rubo77 Jun 22 '14 at 9:24
  • 1
    This script doesn't work. Just tested it on Red Hat linux... The else block always runs, even when the spacebar is pressed. – robert Dec 22 '15 at 6:56
  • 3
    @robert It's because you don't use bash. It works if you use read _ instead, if you have some other shell than bash. – Niklas Rosencrantz May 2 '16 at 9:48
  • Should the '' contain a space inside? – Jose Antonio Reinstate Monica Nov 29 '16 at 10:37
  • This is'' for an empty string. No space inside. I guess, it also fits, if you enter ENTER or TAB – rubo77 Jan 10 '17 at 7:01
46

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

  • I mean why the $ before the string in here: -rsp $'Press ? – rubo77 Jun 4 '14 at 22:44
  • 2
    @rubo77 - ah. That's how you can do a literal string with special characters. It's of the form: $' ... ' – slm Jun 5 '14 at 0:38
  • 1
    @rubo77 - that's different. That's a dollar sign w/ double quotes, I used a dollar w/ single quotes. Please delete that comment, it's wrong. – slm Jun 5 '14 at 7:37
  • 1
    Ah, I understand. In case you put escaped sequences inside the prompt-string. see wiki.bash-hackers.org/syntax/quoting#ansi_c_like_strings – rubo77 Jun 5 '14 at 7:57
  • @rubo77 - yes that notation allows for escape sequences to be included w/o any extra echo -e "..." lines. It's much more compact in those situations. – slm Jun 5 '14 at 7:58
6
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
5

You could create a function for it:

pause(){
 read -n1 -rsp $'Press any key to continue or Ctrl+C to exit...\n'
}

Then you can use this everywhere in your script:

pause
  • if you are new to shell scripting - you need to put the function at the top of your script before using it – Richard Mar 24 '16 at 16:54
3

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.

2

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
1

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!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.