Let's say I'm running a process and it does a very lengthy procedure, printing its progress to the stdout. Is there a way to terminate the process automatically after
- x lines of output
or - a certain keyword has been found in the output?
I'm currently already piping the output of command x
to egrep 'search pattern
and want to terminate x
after egrep
shows a particular line.
I imagine if there were some way to script:
run command `y` after `x` lines of output are seen on previous apps piped `sdout`
I could pull it off fairly easily, for example:
mylongrunningtool | egrep '(term1|term2)' | runafterxlines --lines=8 --command='killall -9 mylongrunnigtool`
Any takers?
Best Answer
Try the
head
command:head
allows you to specify the number of lines. Refer to the man page for more info.loop.py
:loop.py
should run infinitely, but if I pipe its output tohead
, I get:Note that the error (
Traceback ...
) portion is actuallystderr
, as demonstrated by running./loop.py 2> stderr.log | head
, so you need not worry about grepping the output of head.Finally, to search:
Here, I've redirected
stderr
ofloop.py
out of the way even though we're certain it won't interfere with the text processed byhead
andgrep
EDIT
TL;DR: The CPU scheduler controls just how much the intensive process will run after
head
completes its output.After some testing, I found that my solution, though it does cut the execution of
loop.py
, isn't as robust as one can make it. With these modifications to myloop.py
, piping its output to head yields:new
loop.py
:and the output:
I've hidden some of the output and left only the relevant parts. In essence, the output shows that
head
's (and I guess all processes') standard input/output streams are buffered.According to this answer on SO, once the receiver (
head
) terminates, the pipe gets broken, and *only when the sender (loop.py
) attempts to write to the now-broken pipe* will a SIGPIPE signal be sent to it.So when
head
got the chance to print its output, all of it showed up at once, but only afterloop.py
continued for another 247 lines. (This has to do with the scheduling of processes.) Moreover, afterhead
had printed its output but before it terminated, the scheduler resumedloop.py
, so another ~250 lines (up to 488) were written to the pipe before the pipe was broken.For better results, we can use unbuffered I/O (in this case, unbuffered output of
loop.py
). By invoking the python interpreter with the-u
option, we get:Of course, this is straightforward if your program is written in python, as you don't need to make modifications to the code. However, if it is in C, and you happen to have the source for it, you can use the function
setvbuf()
instdio.h
to setstdout
as unbuffered:loop.c
: