shellsubshellbash-trap

Trap signals both in script and subshells


I know there's a lot of questions similar to mine, but I didn't found any about trapping signals sent when a subshell is taking place on the terminal. Let me explain:

#!/bin/sh

trap 'echo "exiting.."; exit 0;' INT

var1=$(echo "ab\nab" | fzf)
var2=$(echo "cd\ncd" | fzf)

fzf is a tool to display a selector of items of a list, so when the program reaches var1 a pretty selector covers my terminal screen prompting ab in one line and ab in the second, with the arrow keys I select the desired one and the result gets printed. Looks a lot like dmenu using this way.

The problem is that Ctrl-C doesn't get trapped by the script when fzf is prompting those lines. Instead, Ctrl-C kills fzf but the script keeps running.
So the question here is more about how to propagate this signal to the parent process.


Solution

  • There is no easy way to propagate the particular signal from child to parent. However, exit code is 130 if the program is terminated by Ctrl-C in many cases. fzf follows it also. Checking exit status and sending signal to own process is one of the workaround.

    #!/bin/sh
    trap 'echo "exiting.."; exit 0;' INT
    
    var1=$(echo "ab\nab" | fzf)
    [ $? -eq 130 ] && kill -INT $$
    var2=$(echo "cd\ncd" | fzf)
    [ $? -eq 130 ] && kill -INT $$
    

    However, it is not common way. If it needs to do something when terminated with any errors, using set -e and trapping EXIT or other signals is general way.

    #!/bin/sh
    set -e
    trap 'echo "exiting.."; exit 0;' EXIT
    
    var1=$(echo "ab\nab" | fzf)
    var2=$(echo "cd\ncd" | fzf)