views:

516

answers:

1

I would like to start a long-running command-line process in my Grails application, log each line of output to the console when it arrives, and do other stuff asynchronously, while the process and logging activities keep going. (At some point, I'll want to do something else with each line of output, like log to a file or look for certain values and trigger other actions. But logging to the console is fine for the purposes of this question.)

Below is the code I came up with to do this. It works, but starting the logger thread without expressly terminating it bothers me a bit - will it terminate properly? can it become a zombie? I'd rather tell Groovy to send process output directly to the System.out stream - something like command.execute(outputStream=System.out) - but haven't found a non-blocking way to do that. Can you suggest a better way?

def runCommand(command) {
    def process = command.execute()
    def out = process.getInputStream()
    def logger = Thread.start { out.eachLine { println it } }
    process.waitForOrKill(TIMEOUT_IN_MILLIS)
    return process // use to get exit code et cetera
}
+1  A: 

Looking at the Groovy docs for Process, I saw that there was a method consumeProcessOutput(OutputStream output, OutputStream error). I tried rewriting your method in the following way, hoping that it would be non-blocking:

def runCommand(command) {
  def process = command.execute()
  process.consumeProcessOutput(System.out, System.err)
  println 'requested consume output' //hoping this will come out first
  process.waitForOrKill(TIMEOUT_IN_MILLIS)
  return process // use to get exit code et cetera
}

When I ran it on Windows XP with the command 'dir', I got the following output:

requested consume output
file1    file2  ...

Success! :)

Matt Passell
Yep, that works great! For some reason I was expecting some magic in the execute() method, not on the Process object it gives you back. Thanks!
Douglas Squirrel