I am running a simulation like this
./waf --run scratch/myfile | awk -f filter.awk
How can I kill the waf
command as soon as filter.awk
detects that something happened (e.g. after a specific line is read)?
I cannot change waf
or myfile
. I can only change filter.awk
, and the above command (obviously).
Update after comments:
waf
does not terminated after receivingSIGPIPE
(as it should?)- It spawns child processes, that need cleaning up.
This is my own answer (and challenge).
After working on @thatotherguy's ans @Chris's answers, I simplified a bit and got this:
tmp=$(mktemp)
{ ./waf --run scratch/myfile & echo $! > "$tmp"; } | { awk -f filter.awk; pkill -P $(<$tmp); kill $(<$tmp); }
Unfortunately I could not get rid of the tmp
file, every attempt to pass the PID
as a variable failed.
I won't change the accepted answer (since it was the one that worked when it was really needed), but +1 for anyone that can simplify more.
Use
awk
'sexit
statement.waf
should exit as soon as the pipe connecting it toawk
closes.What makes this tricky is that
waf
misbehaves by not exiting when the pipe breaks, and it spawns off a second process that we also have to get rid off:<(process substitution)
to runwaf
in the background and write its pid to a temp file.cat
as an intermediary to relay data from this process to awk, sincecat
will exit properly when the pipe is broken, allowing the pipeline to finish.waf
has spawned (by Parent PID)waf
itself.When
awk
exits,waf
gets aSIGPIPE
the next time it tries to write output, which should cause it to exit unless whoever wrotewaf
deliberately set it up to ignoreSIGPIPE
s telling it to exit, in which case you'll have to kill it manually withkill
or some such. Something like:You might need a
-KILL
option tokillall
ifwaf
is ignoring all exit signals.