Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trapping ctrl+c in a bash script after a read in silent mode

Tags:

bash

shell

The script I'm working on reads in a single character in silent mode and stores it to $c

Heres a tester script which does the same thing as an example:

    #!/bin/bash

    gracefulExit() {
          echo "exiting..."
          #other stuff would go here
          exit 1
    }

    trap gracefulExit INT

    while [ 1 = 1 ]
    do
          read -s -r -n1 c
          echo "character read"
    done

The problem I'm having is that if you use ctrl+c to break out of the script, the shell stays in silent mode (I can't see anything I type) and it won't return to normal until I exit. I noticed this only happened after I was trapping ctrl+c (without the trap, its kicked from silent mode). My script requires me to trap so I can clean up.

This is on 4.2.10

Any ideas?

Thank you very much for your help!

like image 600
iamhungry129 Avatar asked Mar 27 '14 06:03

iamhungry129


People also ask

How does bash handle Ctrl-C?

You can use the trap builtin to handle a user pressing ctrl-c during the execution of a Bash script. e.g. if you need to perform some cleanup functions.

How do you prevent Ctrl-C cause the termination of a running bash script?

How do I disable Control-C? You need to use the trap command which can enable or disable keyboard keys such as Crtl-C. SIGINT is Crtl-C and it is represented using number 2. Signal names are case insensitive and the SIG prefix is optional.


1 Answers

Try to reenable the tty echo in the exit function:

#!/bin/bash

gracefulExit() {
      echo "exiting..."
      # reenable tty echo
      stty icanon echo echok
      exit 1
}

trap gracefulExit INT

while [ 1 = 1 ]
do
      read -s -r -n1 c
      echo "character read"
done

In my test on OS X read disabled these settings: icanon echo echok. You can check that for your system with stty -a

Run it before you call your script and then again after your script finished and check the difference in the output to identify what you program changed. Then set the changed flags back.

$ diff before.out after.out
2,3c2,3
< lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl
<   -echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
---
> lflags: -icanon isig iexten -echo echoe -echok echoke -echonl echoctl
>   -echoprt -altwerase -noflsh -tostop -flusho -pendin -nokerninfo

here you can see the changed flags: icanon, echo, echok got disabled. You can identify that with the "-" at the beginning.

and finally here's another version of your script that does the full job automated:

#!/bin/bash

# save the current tty flags
tty_flags=`stty -g`

gracefulExit() {
      echo "exiting..."
      # set the saved tty flags
      stty $tty_flags
      exit 1
}

trap gracefulExit INT

while [ 1 = 1 ]
do
      read -s -r -n1 c
      echo "character read"
done
like image 189
tony994 Avatar answered Oct 09 '22 23:10

tony994