我的情况类似于Redirect Stdin and Stdout to File。我想运行一个程序并捕获运行程序的整个会话(stdin和stdout),好像它是从终端以交互方式运行的。
从Dump terminal session to file我发现script
命令可行。这是我的程序的简化版本(用Groovy编写),它可以做到这一点。
import groovy.io.GroovyPrintWriter
def OUTPUT_FILE = "output.txt"
def sysout = new StringBuffer()
def syserr = new StringBuffer()
// On Linux (Ubuntu 12.04) - starts the bc command with script and capture session to OUTPUT_FILE
Process proc = "script -q -f -c bc ${OUTPUT_FILE}".execute()
// On OS X with a slightly different version of Script
// Process proc = "script -q ${OUTPUT_FILE} bc".execute()
proc.consumeProcessOutput(sysout, syserr) // Spawns separate threads that will consume the out to prevent overflow
proc.withWriter { writer ->
// Writes the following commands to the spawned process
def gWriter = new GroovyPrintWriter(writer)
// Imagine that the user enters these lines
gWriter.println "a = 5"
gWriter.println "b = 4"
gWriter.println "c = a * b"
gWriter.println "c"
gWriter.println "quit"
}
proc.waitForOrKill(20000) // Give it 20 seconds to complete or kill the process
println 'Standard out captured from process:\n' + sysout
println 'Standard err captured from process:\n' + syserr
我编写的程序适用于OS X上可用的脚本版本。在OS X上,整个会话都在sysout变量中捕获,并且也正确写入OUTPUT_FILE。
以下是我希望得到的内容
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. a = 5
b = 4
c = a * b
c
20
quit
然而,这就是我在Linux上获得的(Ubuntu 12.04),它省略了输入STDIN的所有内容,只捕获了STDOUT。这是sysout和OUTPUT_FILE
的内容bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
20
如您所见,缺少a = 4, b = 5, etc
行。
当我从命令行提示符(script
)在Linux上手动运行script -q -f -c bc output.txt}
命令并逐行输入时,它会起作用,即所有行也写入OUTPUT_FILE。 / p>
要让我的程序在Linux上运行,还需要执行哪些其他步骤?我知道该程序适用于OS X,因此它不太可能是程序(或Groovy)的问题。我怀疑它必须与Linux版本的脚本在作为外部进程启动时的行为方式有关。
任何指针都会受到赞赏。
答案 0 :(得分:0)
我不确定为什么会在Ubuntu上而不是在OS X上发生这种情况,但是在Ubuntu上可能的解决办法可能是用你自己的类来装饰编写器,该类将写入的字符附加到StringBuffer。
它不是非常漂亮,因为您必须添加特定于操作系统的代码,以确保OS X上的输出不包含两次。
无论如何,这里是装饰程序类的完整脚本,使用Groovy 2.0.5在Ubuntu 12.04上运行正常。
import groovy.io.GroovyPrintWriter
def OUTPUT_FILE = "output.txt"
def sysout = new StringBuffer()
def syserr = new StringBuffer()
// On Linux (Ubuntu 12.04) - starts the bc command with script and capture session to OUTPUT_FILE
Process proc = "script -q -f -c bc ${OUTPUT_FILE}".execute()
// On OS X with a slightly different version of Script
// Process proc = "script -q ${OUTPUT_FILE} bc".execute()
proc.consumeProcessOutput(sysout, syserr) // Spawns separate threads that will consume the out to prevent overflow
proc.withWriter { writer ->
// Writes the following commands to the spawned process
def gWriter = new GroovyPrintWriter(new MyCaptureWriter(writer, sysout))
// Imagine that the user enters these lines
gWriter.println "a = 5"
gWriter.println "b = 4"
gWriter.println "c = a * b"
gWriter.println "c"
gWriter.println "quit"
}
proc.waitForOrKill(20000) // Give it 20 seconds to complete or kill the process
println 'Standard out captured from process:\n' + sysout
println 'Standard err captured from process:\n' + syserr
class MyCaptureWriter extends Writer {
@Delegate OutputStreamWriter writer
def sysout
MyCaptureWriter(writer, sysout) {
this.writer = writer
this.sysout = sysout
}
@Override
void write(char[] cbuf, int off, int len) throws IOException {
sysout.append(cbuf, off, len)
writer.write(cbuf, off, len)
}
}