1

I am looking for a clean method to start and stop java processes based on stdout. Basically I want to go through a for loop in Bash that starts a java command with input variables, monitors stdout for a specific string "Results:" and then kills that same process, then goes to the next one, starts a new java process and continues.

I have tried working with coproc but have not been able to get anything close to working as intended.

Chris Moretti
  • 585
  • 3
  • 13
  • 31
  • put your code that you already wrote. – Shakiba Moshiri Feb 06 '17 at 17:37
  • That is kind of the problem. I wrote the basic logic of the script (the java command I am trying to run, the for loop structure to run the java command based on a config file that is in a conf directory, etc.) But when it comes to the logic I am listing above, I don't even have any idea where to start...I am fairly basic in my bash knowledge/experience – Chris Moretti Feb 06 '17 at 19:52

3 Answers3

1

I would use screen. It works for most of my scripts:

Start session named myjava command

screen -dmS myjava sh -c "/path/to/script.name parameters > /tmp/outfile"

here you wanted to monitor the /tmp/outfile with bash ... (tail -f or something)

and a kill your session myjava with

screen -X -S myjava kill
jaromrax
  • 274
  • 1
  • 12
  • So in this context, I am going to assume that you are storing the java command in a variable "myjava" and then using that same designation to kill that same command? Where would I be informing the script WHEN to kill the process...when I find the correct line of output in the stdout...how does it know when that pops up? – Chris Moretti Feb 06 '17 at 17:38
  • Oh I see. myjava is a name for the screen session. Select whatever name. You say you will monitor the stdout from the bash, so I suppose you already know how to do that. Anyway, I clarify a bit the answer – jaromrax Feb 06 '17 at 17:42
1

You can use coproc like so:

coproc java …
grep -q -m1 'Results:' <&$COPROC && kill $COPROC_PID 

This will have grep read from the java output and kill it as soon as it sees a matching line.


If you want to see the output of the java command instead of doing this silently, use tee to both print the output and send it to the grep … && kill … group.

coproc java …
tee <&$COPROC >(grep -q -m1 'Results:' && kill $COPROC_PID)
Grisha Levit
  • 8,194
  • 2
  • 38
  • 53
  • This definitely seems like the way to go. For some reason, when I run the java command, it hangs and never gets to the 'Results:' string. If I run the command by itself, it works fine. But with the coproc tag in front, it doesn't seem to be outputting all of the normal stdout stream. – Chris Moretti Feb 09 '17 at 17:50
  • Do you see *any* output when you try the second form (with `tee`)? – Grisha Levit Feb 09 '17 at 18:43
  • Yes. It spits out a few warnings about log file configuration (which is normal output...expected) but then it just hangs and never reaches the 'Results:' line. – Chris Moretti Feb 09 '17 at 20:11
  • So it gets to just before the Results line? Maybe this works but the process doesn't respond to kill? You could try `kill -9 $COPROC_PID`. Alternatively, the process might be detecting that it's not writing to a terminal? Does the correct output get generated when you run the java command piped to grep or redirected to a file? – Grisha Levit Feb 09 '17 at 21:00
  • Also, is the `Results:` text followed quickly by a newline? Might want to an `-o` to the grep if not. – Grisha Levit Feb 09 '17 at 21:10
  • So basically what it looks like is happening is that the java command I am running starts client. The client startup outputs some standard log configuration errors to stdout. Those show up. Once the client starts, there are some echo statements that get spit out to stdout. One of those is the 'Results:' line. When I run the coproc in front of the java command, the echo statements never show up...almost like it is only running the process but the rest of the output from the actual client is getting routed somewhere else. – Chris Moretti Feb 09 '17 at 21:18
  • Any ideas? I am still having this issue and it is really confusing. – Chris Moretti Feb 13 '17 at 12:49
  • It's kind of hard to guess without a lot more information about specifically how "the java command starts a client". One possibility is that it's starting the client in the background and then exiting. You may want to have the `kill` command target the whole process group then, like `kill -TERM -$COPROC_PID` – Grisha Levit Feb 13 '17 at 17:45
  • Yea that didn't work. I feel like this concept works, I am just confused as to why it is behaving differently. If I run the java command alone, it outputs fine and gets to "Results:" but when I place it inside a bash script, in a for loop and use the coproc, it outputs the initial Log warnings and then just sits there. The loop stops and doesn't continue, probably because it is looking for the 'Results' line and it never shows. – Chris Moretti Feb 14 '17 at 15:02
0

Assuming your Java code just exits on its own when it receives SIGPIPE, you can just pipe the output to grep and have grep exit as soon as it sees a match. Assuming you are using a version ofgrepthat supports the-moption (GNU and BSDgrepboth do), you can havegrep` exit after the first match:

java ... | grep -m 1 'Results:'

One slight catch: because of buffering, your java program may continue to run for an abitrarily long time before grep actually sees the "Results" line.


Using only standard grep, you can use tee to both display the output and exit after finding any match.

java ... | grep 'Results:' | tee | grep -q '.*'

This suffers the same buffering issue, but amplified: not only may the first grep have to wait before it actually receives the "Results" line, but tee may similarly need to wait before it finally gets the same line. Further, if the line is too small, the first grep may never produce any more output, requiring you to wait for java to exit naturally before tee ever sees any input.

chepner
  • 497,756
  • 71
  • 530
  • 681