logoalt Hacker News

packetlost • yesterday at 10:16 PM • 1 reply • view on HN

> The parentheses are absolutely crucial there for some reason, the { } won't give you pass-through of SIGINT.

This is a gross misunderstanding of what is going on (signals are never "passed through", the process is either in the same group or it isn't), but the real issue here is the confusing semantics of bash's job controls. I personally would have swapped the semantics of { command blocks } and ( subshells ) too, but bash is pushing 40 so maybe it made more sense then.

It will sorta behave properly if you disable job control or put it in a script:

    set +m
    {
        trap 'kill 0' SIGINT;
        for i in {1..$N}
        do
            whatever_command $i &
        done
        wait
    }
it might also kill your current shell too though. This really seems to boil down to not understanding the difference between { } and ( ) in bash.

Replies

Joker_vD • yesterday at 10:31 PM

> signals are never "passed through", the process is either in the same group or it isn't

Yes, I know. It's actually a major nuisance because sometimes you do want to pass the signals through, e.g. to implement termination of all transitive children processes, process groups notwithstanding, so then you have to do it yourself.

> it might also kill your current shell too though.

It absolutely will kill your current shell, but only if it's non-interactive — so that's a funny way to have a script that misbehaves when ran non-interactively, but works as intended when you try to debug it. So, you either need a subshell (and then the subshell having a fresh process group makes it mostly work on its own), or fake it with "trap 'jobs -p | xargs -n 1 kill -SIGINT' SIGINT" bullshit or the like (for all the signals you can remember). The subshell way is somewhat more robust.

➕ show 1 reply