1

I have a master script that controls some satellite scripts. When I send the interrupt signal from the terminal, the parent's traps caught the signal, but the child's didn't, which I can't figure out why. I didn't change the default terminal setting (I didn't run stty anywhere).

Here's my parent and child script and terminal output:

parent:

#!/bin/sh

./child.sh &

for sig in $(kill -l) ; do
    trap "echo parent:$sig" $sig
done

wait

child:

#!/bin/sh

cat < /dev/tty &
PID=$!

for sig in $(kill -l) ; do
    trap "echo child:$sig" $sig
done

wait

terminal interaction:

[prompt]$ ./parent.sh
^Cparent:INT
cat: stdin: Input/output error

[prompt]$

Update

I tested the script on macOS and CentOS, the behavior describe above occurs. When I test it on FreeBSD using the default Bourne-compatible shell, the signal child receives is CHLD.

1 Answer 1

2

For commands run asynchronously by non-interactive shells (actually when job control is not enabled), SIGINT and SIGQUIT are ignored in POSIX compliant sh implementations. That's a POSIX requirement though some shells ignore it.

Another POSIX requirement is that if a signal was ignored upon start of the shell, you can't unignore it, so you're screwed.

Here, you could use zsh instead of sh which doesn't have either of those annoying "features" (at least in current versions).

In any case signal handling in shells is one of the least reliable and portable aspects. You'll find behaviours vary greatly between shells and often between different versions of a same shell. Be prepared for some serious hair pulling and head scratching if you're going to try to do anything non-trivial.

I'd recommand using a different language where you can have a finer control over what happens.

Also, I wouldn't blindly handle every possible signal, only the ones you're expecting to receive and know how you can handle. Trapping SIGCHLD for instance (which the shell itself is interested in as it's its job to spawn processes and handle their termination) is likely not to do what you want.

2
  • @zevzek, that very much depends on the shells, some use wait*(), some use a handler on SIGCHLD and get the info from siginfo_t. For having tested a few years ago, IIRC, some let you trap SIGCHLD, some don't. Oct 16, 2020 at 9:51
  • @zevzek, what I meant was that it was unlikely to do what you want whatever it is. You can try "$shell" -c 'trap uname CHLD; id; exit' and compare between shells. You'll find some run uname in a loop, some don't run it at all, some run it once. Oct 16, 2020 at 10:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.