I need help understanding exactly how SIGINT is propagated between a shell script's main flow and a function call inside that script. For my script, I have a main menu which takes user input and calls a child function based on that input. The child function interacts with the user.
My goals are the following:
- I need the child function to have access to function definitions and variables from the main script, so subshells aren't a great option
- The child function should be in its own file because otherwise my main shell script would be too big and unwieldy
- I want a ctrl+c inside the child function to return the user to the main menu
- I want a ctrl+c inside the main menu to ideally print something, and if done again, exit. If it has to exit the first time that is acceptable
The behavior I see is that I can hit ctrl+c either inside the main menu or from inside the child function and it will work as expected the first time, but all subsequent ctrl+c signals are ignored.
I feel like my issue is very close to these:
- https://unix.stackexchange.com/questions/240602/how-can-i-handle-sigint-trap-with-a-user-prompt-in-shell-script
- bash: Why can't I set a trap for SIGINT in a background shell?
Though in their case they are calling the child in a new process, and I'm calling a sourced function, which I don't think would have the same implications for fg/bg, would it?
For a minimal example, let's say I have a file called main.sh:
trap catchInt SIGINT
reallyQuit=0
function catchInt(){
echo "caught sigint"
if (( $reallyQuit > 0 ));then
echo "really quitting."
exit 1
else
let reallyQuit++
echo "reallyquit is now $reallyQuit"
fi
menu
}
function menu(){
read -ep $'Please choose a number and press enter.\n\t' input
case $input in
1)
child
menu
;;
*)
echo "Quitting"
exit 0
;;
esac
}
source child.sh
# I also source other scripts with utility functions and exported vars
menu
And if I have a file called child.sh in the same directory:
function child(){
read -p "Please type something"
# I also use utility functions and exported vars
}
Here is an example run of the above code in which I hit ctrl+c inside the menu, and then try again inside the child function:
bash main.sh
Please choose a number and press enter.
caught sigint
reallyquit is now 1
Please choose a number and press enter.
1
Please type something^C^C^C^C^C (I finally pressed enter)
Please choose a number and press enter.
(I tapped ctrl-c a few times here and finally pressed enter)
Quitting
Here is an example in which I first type 1, then ctrl-c:
bash main.sh
Please choose a number and press enter.
1
Please type something^Ccaught sigint
reallyquit is now 1
Please choose a number and press enter.
(I tapped ctrl-c a few times here and finally pressed enter)
Quitting
How can I get the trap to respond every time I send the INT signal?