Bash script doesn't catch SIGINT while in read loop
I have several scripts with while read line
loops that don't execute my cleanup function when I press Ctrl C. For example:
#!/bin/bash
cleanup() {
stty echo
exit 0
}
trap cleanup SIGINT SIGHUP SIGTERM
stty -echo
while read -r line; do
echo "$line"
done < /foo/bar
cleanup
When I press Ctrl-C, my terminal is screwed up because the stty -echo
setting is still in effect. I have many other scripts where my cleanup function works flawlessly. The only time I seem to have a problem is when I press Ctrl-C while the script is in a read
loop. Is there a way to ensure that the cleanup
function will get called when Ctrl-C is pressed while the script is inside a read
loop? Or am I just missing something obvious here?
Update: There is something else going on in my scripts. I ran the exact script above, and I can't get it to fail the way my other scripts do. I will have to try to distill the broken scripts down to something that I can get to fail, at which point I will update the question.
Update 2: Okay, I figured it out. I was getting an error from stty
(which I wasn't seeing because my real cleanup function was also clearing the screen). The error was: stty: standard input: Inappropriate ioctl for device
. I looked this up an apparently it was due to calling stty
while stdin
was redirected from the file /foo/bar
. So I changed my trap
call to trap "break" SIGINT SIGHUP SIGTERM
and it worked.
It turns out the problem was due to the fact that my cleanup
function was calling stty
, and stty
evidently doesn't like to be called while stdin
is being redirected from a file. Thus, when I pressed Ctrl-C while the script was executing the read
loop, the cleanup
function got called as if I had called it from within the loop:
while read -r line; do
...
cleanup
...
done < "$filename"
This, in turn, meant that stty
was executed with a redirected stdin
, and it died with the error stty: standard input: Inappropriate ioctl for device
.
I was able to fix this by changing my trap
line:
trap "break" SIGINT SIGHUP SIGTERM
So instead of having it effectively insert a call to cleanup
into my loop when I press Ctrl-C, it instead just (effectively) inserts a break
into the loop, thus breaking out of the loop and subsequently calling the cleanup
function via the line after the loop.
上一篇: GHC GC'ing火花