8

I want to spawn two child processes, but wait until the first reaches a certain point in its execution (which can be determined by examining stdout) before spawning the second. I'm not sure which unix commands would be involved in accomplishing this, and have had a hard time finding anything via google due to the terse and sometimes cryptic nature of unix command names.

I'm not seeking a solution to the specific problem I'm trying to solve (although any additional pointers would be appreciated), I'm primarily concerned with knowing which unix commands I'd want to look up and learn to use.

| |
  • Are you open to using Python? – xrisk Feb 17 '18 at 5:53
  • 3
    Without knowing how you determine the "certain point in its execution", this is very vague. – muru Feb 17 '18 at 7:19
  • @muru edited to clarify – w.brian Feb 17 '18 at 13:35
  • So you actually need 3 processes. 1. runs, creating output; 2. monitors the output of 1, and at a certain point starts 3. This is enough info to get you started making whatever it is you're making. But it's not a good way of designing a program. – djsmiley2kStaysInside Mar 14 '18 at 10:31
7

You can use the xargs utility for this. It can run a command for each line on stdin, so we just need to ensure that xargs gets as input a single line on stdin at the time it should start the command, which can be accomplished with grep:

proc1 | grep --max-count=1 "${targetString}" | xargs --max-lines=1 --no-run-if-empty --replace -- proc2

The arguments --max-count=1, --max-lines=1 and --no-run-if-empty ensure that proc2 is started exactly once if and when proc1 outputs ${targetString} for the first time, and never if proc1 never outputs ${targetString}. The --replace avoids that xargs appends the input line to its command line.

I used the following command line to test it:

(echo Start >&2; sleep 3 ; echo Trigger; sleep 3; echo End >&2) | grep --max-count=1 Trigger | xargs --max-lines=1 --no-run-if-empty --replace -- echo "Triggered"
| |
  • 1
    +1 This is a very creative answer. It would get considerably more complicated though if you need the rest of the output from proc1. You'd need to use things like tee and additional file descriptors or named pipes. – Joe Feb 20 '18 at 11:12
7

I'm not sure there is an elegant command / answer to the question you asked (i.e. reach a certain point in its execution) - but there are tools / techniques which can be used to bodge up a solution, probably involving more than 1 of the following, and maybe other things I don't know about yet:

  1. Backgrounding processes (&)
  2. Conditional execution (&& and ||)
  3. sleep
  4. wait (I expect this will be particularly useful - if you launch more than 1 job in the background, it will wait until all the jobs are completed)
  5. Named pipes (which could provide a mechanism to talk between processes).
  6. inodenotifywait

Writing and checking lock files is also common practice (pro tip - if you have control of the environment, write to the ramdisk rather than /tmp - on many distros this is /dev/shm).

| |
6

This is just an idea, but have the first process pipe its output to grep. Have grep pipe its output to a read line loop, and compare each line with what you're looking for. Once found, execute proc2.

#!/bin/bash
targetString="line you are looking for"
proc1 | grep "${targetString}" |
while read line
do
if [ "$line" = "${targetString}" ]; then
    proc2
fi
done

If "a certain point in its execution" can be determined by stdout, then how about the following?

proc1 | grep "stdout trigger string" && proc2

&& should fire when grep returns 0, which it only does when it finds a match.

| |
  • 1
    grep will keep going until stdin is closed. It won't return anything (0 or otherwise) until then. – Bob Feb 17 '18 at 5:38
  • @Bob Oh, thank you... I'll try to rephrase this idea. – Louis Waweru Feb 17 '18 at 5:44
  • @bob It would be particularly messy and disjointed, and a misuse of the tool, but you could use fail2ban to monitor a log file (ie pipe stdout to a file), and then program a rule to execute the second script when that line is found (but I recon modifying a trigger file and using inotify is a more elegant solution) – davidgo Feb 17 '18 at 8:28
  • 1
    If targetstring occurs more than once in proc1 output, proc2 will be run multiple times. If you did proc2 & and then break, that wouldn't happen, but that would close the pipe and make proc1 terminate prematurely. Alternatively, you could set a flag once proc2 is started and use it to make sure proc2 is not run again. As with the other answer, the rest of proc1 output is discarded, so if you need it, more work is necessary. – Joe Feb 20 '18 at 11:26
  • 1
    @Joe Good point. The original question was actually just asking about what commands were available to work with, so this is really just an answer demonstrating some of those commands' potential (mainly | and grep here). – Louis Waweru Feb 22 '18 at 0:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.