MaxB MaxB - 2 months ago 5x
Linux Question

Can't kill a Bash command that sleeps in a loop

I tried to run

$ (while true; do cat some_small_file ; sleep 1; done) | some_script

to test
, but
wasn't in my
, so that printed

some_script command not found

The weird things is that
did not return, and
does nothing.

I even tried killing

ps -u maxb | grep sleep | cut -f1 -d " " | xargs kill -9

in another terminal, but that, of course just continues to the next loop iteration.

Is it possible to make
terminate that command?


There are a few approaches you can take here.

One is to move both cat and sleep into the conditional part of the while syntax, such that the loop will fail as soon as either of those commands does not succeed:

{ while cat some_small_file && sleep 1; do :; done; } | some_script

A similar option is to put an explicit break into the loop, conditioned (again) on such failure:

{ while :; do cat some_small_file && sleep 1 || break; done; } | some_script

Note that : is an exact synonym for true. (In every shell I've seen -- not just bash but even Busybox ash -- they're literally implemented by the same internal function).

Also note that the most important part of this solution is exiting the loop if cat fails, not if sleep fails: Exiting on a sleep failure will address the kill problem, but exiting on a cat failure will handle the (much more likely) case that some_script has exited and thus writing to it is resulting in a SIGPIPE.

By the way -- the change from ( ) to { ...; } is to potentially reduce the number of transient subshells: While pipelines always create implicit subshells, there's no particular reason to use syntax that may (in some cases -- there are pertinent details which are implementation- rather than standard-defined) create an explicit subshell in addition to the mandatory implicit one(s).

It's thus a very minor efficiency improvement, but not essential to this answer: You'd get the same behavior if you stuck with the original parenthesis but modified the flow control constructs in the same way.