我如何将进程的 stdout、stderr 和 stdin 重定向到 Groovy 中的文件以及从文件重定向,就像在 Bash shell 中一样?
How do I redirect a process' stdout, stderr and stdin to and from files in Groovy, like in the Bash shell?
我正在将 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 作为中间人删除。
所以,我的问题是:如何将文件重定向到 stdin
和 stdout
以及 stderr
文件,以便可以分离外部进程Groovy 不需要 运行?
编辑: 这个问题 不是 capture process output in Groovy 的重复,因为那个问题涉及重定向 stdout
和 stderr
到 Groovy 进程本身的 stdout
和 stderr
。从@tim_yates` 的回答可以看出,这是完全不同的事情。
为什么不直接利用 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
)
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()
returns一个java.lang.Process
,由Groovy装饰。 waitForOrKill
等方法仍然有效。
我正在将 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 作为中间人删除。
所以,我的问题是:如何将文件重定向到 stdin
和 stdout
以及 stderr
文件,以便可以分离外部进程Groovy 不需要 运行?
编辑: 这个问题 不是 capture process output in Groovy 的重复,因为那个问题涉及重定向 stdout
和 stderr
到 Groovy 进程本身的 stdout
和 stderr
。从@tim_yates` 的回答可以看出,这是完全不同的事情。
为什么不直接利用 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
)
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()
returns一个java.lang.Process
,由Groovy装饰。 waitForOrKill
等方法仍然有效。