Search code examples
bashsignalsstty

trap "stty echo" INT has no effect when used with read -s


Given this bash script:

stty -echo
echo $(stty)

reset() {
        stty echo
        echo $(stty)
        exit
}

trap reset int
read -s
sleep 10

I expected the echo option to be enabled, but after pressing ctrlc it is still disabled, even though I have ran stty echo (as you can see in the output by the reset function).

terminal picture


Solution

  • As @KamilCuk has noticed in the comments, read saves the configuration and restores it when the process exists. That results in modifications done while read was running being discarded. The solution is to restore the defaults before running read and redoing them after read finishes.

    stty -echo
    echo $(stty)
    
    reset() {
            stty echo
            echo $(stty)
            exit
    }
    
    trap reset int
    
    stty echo # This line has been added
    read -s
    echo read finished
    stty -echo # This line has been added
    
    sleep 10
    

    @JonathanLeffler also noted that

    It can be useful to use old=$(stty -g) to capture the current terminal settings, and then use stty "$old" to reinstate those settings.

    Explaination:

    Using it allows you to reinstate the exact terminal settings when stty -g was invoked. This can be more reliable than undoing changes with stty -echo etc.

    Which I think is the more proper solution, as the stty may run in no-echo mode by default.