I have a text-based user interface script that allows me to browse directories and select a file. The graphics are output to stderr
, the chosen file's path is sent to stdout
. This allows to get the chosen file this way:
file="$(./script)"
This is very handy, as command substitution only grabs stdout
.
But I need my script to handle signals, so that when the script is interrupted, it can reset the display. I set up a trap that handles the INT
signal. To simulate what it's doing, consider the following script:
catch() {
echo "caught"
ps # Calling an external command
exit
}
trap catch INT
while read -sN1; do # Reading from the keyboard
echo $REPLY >&2
done
The script is then called with var="$(./script)"
. Now, if you send the INT
signal by hitting ^C
, the parent shell breaks: Anything you type (including control characters) will be printed out until you hit return, then none of your inputs will be shown.
Removing the external command call in the catch
function seems to fix the issue (still, the echo
doesn't seem to work), but I don't understand why, and I can't do without it in my final script.
Is there something I'm missing? Why does this breaks the parent shell?
As other users seemed to agree that this is a bug, I filed a bug report. I got the following answer:
This is a race condition -- the parent shell handles the SIGINT before it should. This will be fixed in the next devel branch push.
So the best thing to do here is to keep an eye out on Bash's git.
As a "fix", I had to refactor the script to be sourced (. script.sh
), so that it could communicate with the caller without involving temporary files, as process substitution resulted in the exact same behavior than command substitution.