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 receiving SIGPIPE
(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.
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:
tmp=$(mktemp)
cat <(./waf --run scratch/myfile & echo $! > "$tmp"; wait) | awk -f filter.awk;
pkill -P $(<$tmp)
kill $(<$tmp)
- We use
<(process substitution)
to run waf
in the background and write its pid to a temp file.
- We use
cat
as an intermediary to relay data from this process to awk, since cat
will exit properly when the pipe is broken, allowing the pipeline to finish.
- When the pipeline's done, we kill all processes that
waf
has spawned (by Parent PID)
- Finally we kill
waf
itself.
Use awk
's exit
statement. waf
should exit as soon as the pipe connecting it to awk
closes.
When awk
exits, waf
gets a SIGPIPE
the next time it tries to write output, which should cause it to exit unless whoever wrote waf
deliberately set it up to ignore SIGPIPE
s telling it to exit, in which case you'll have to kill it manually with kill
or some such. Something like:
./waf --run scratch/myfile | ( awk -f filter.awk; killall waf )
You might need a -KILL
option to killall
if waf
is ignoring all exit signals.