如何将进程'stdout,stderr和stdin与Groovy中的文件重定向,就像在Bash shell中一样?

时间:2015-02-25 11:09:35

标签: groovy scripting groovyshell

我将Bash shell脚本移植到Groovy。大多数构造都可以很容易地转换(例如mkdir "$foo"foo.mkdir()。但是,我很难理解:

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

运行时,让我们检查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

在Groovy中运行进程可以通过这种方式完成(根据this page):

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

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]

可以看出,文件描述符与其他东西(可能是Groovy进程)相关联。因为这将用于一个长期运行的过程,我想把Groovy作为一个中间人。

所以,我的问题:如何将文件重定向到stdinstdout以及stderr到文件,以便外部进程可以分离,而Groovy则不会需要运行吗?

编辑:此问题capture process output in Groovy的副本,因为该问题涉及将stdoutstderr重定向到Groovy进程本身的stdoutstderr。从@ tim_yates回答可以看出,这是完全不同的事情。

2 个答案:

答案 0 :(得分:1)

ProcessBuilder.redirectOutput()可以解决此问题since Java 7。因为它是标准的Java,所以它也可以在Groovy中使用。

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

结果:

$ 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()返回一个java.lang.Process,由Groovy修饰。诸如waitForOrKill之类的方法仍然有效。

答案 1 :(得分:0)

为什么不利用shell呢?让它做它的设计目的。即:

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

如果需要以编程方式指定输出文件,则只需使用GString:

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

(编辑这两个示例以使用String[]而不是String