How do I redirect a process' stdout, stderr and stdin to and from files in Groovy, like in the Bash shell?

旧巷老猫 提交于 2019-12-24 05:00:40

问题


I'm porting a Bash shell script to Groovy. Most constructs can easily be converted (e.g. mkdir "$foo" to foo.mkdir(). However, I'm stumped on this:

#!/bin/bash
sleep 60 > /tmp/output.log 2>&1 < /dev/null

When running it, let's inspect the file descriptors of sleep:

$ ls -l /proc/$(pgrep sleep)/fd
total 0
lr-x------ 1 user user 64 Feb 25 13:40 0 -> /dev/null
l-wx------ 1 user user 64 Feb 25 13:40 1 -> /tmp/output.log
l-wx------ 1 user user 64 Feb 25 13:40 2 -> /tmp/output.log

Running a process in Groovy can be done this way (according to this page):

#!/usr/bin/groovy
def log = new FileOutputStream("/tmp/output.log")
def sleep = "sleep 60".execute()
sleep.waitForProcessOutput(log, log)

And the file descriptors of sleep:

$ ls -l /proc/$(pgrep sleep)/fd
total 0
lr-x------ 1 user user 64 Feb 25 13:41 0 -> pipe:[522455]
l-wx------ 1 user user 64 Feb 25 13:41 1 -> pipe:[522456]
l-wx------ 1 user user 64 Feb 25 13:41 2 -> pipe:[522457]

As can be seen, the file descriptors tie to something else (probably the Groovy process). Because this will be used for a long-running process, I'd like to cut out Groovy as a middle man.

So, my question: how do I redirect a file to stdin and stdout and stderr to files, such that the external process can be detached and Groovy does not need to be running?

EDIT: This question is not a duplicate of capture process output in Groovy, because that question concerns redirecting stdout and stderr to the stdout and stderr of the Groovy process itself. Which, as can be seen by @tim_yates` answer, is quite a different thing.


回答1:


ProcessBuilder.redirectOutput() can solve this problem since Java 7. And because it's standard Java, it can also be used in Groovy.

#!/usr/bin/groovy
def sleep = new ProcessBuilder('sleep', '60')
                    .redirectOutput(new File('/tmp/output.log'))
                    .redirectErrorStream(true)
                    .redirectInput(new File('/dev/null'))
                    .start();

The result:

$ ls -l /proc/$(pgrep sleep)/fd
total 0
lr-x------ 1 user user 64 Feb 26 11:44 0 -> /dev/null
l-wx------ 1 user user 64 Feb 26 11:44 1 -> /tmp/output.log
l-wx------ 1 user user 64 Feb 26 11:44 2 -> /tmp/output.log

ProcessBuilder.start() returns a java.lang.Process, which is decorated by Groovy. Methods such as waitForOrKill will still work.




回答2:


Why not just leverage the shell? Let it do what it was designed to do. To wit:

#!/usr/bin/groovy
def sleep = (["sh", "-c", "sleep 60 > /tmp/output.log 2>&1 < /dev/null"] as String[]).execute()

If you need to specify the output file programmatically, then just use a GString:

#!/usr/bin/groovy
def outfile = "/tmp/output.log"
String[] sleepCmd = ["sh", "-c", "sleep 60 > ${outfile} 2>&1 < /dev/null"]
def sleep = sleepCmd.execute()

(Edited both examples to use String[] rather than String)



来源:https://stackoverflow.com/questions/28717454/how-do-i-redirect-a-process-stdout-stderr-and-stdin-to-and-from-files-in-groov

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!