BufferedReader.read() 在 运行 perl 脚本使用 Runtime.exec() 时挂起

BufferedReader.read() hangs when running a perl script using Runtime.exec()

我正在尝试从 Java 代码中 运行 一个 perl 脚本,并使用以下代码读取它的输出:

String cmd = "/var/tmp/./myscript";
Process process = Runtime.getRuntime().exec(cmd);
stdin = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while((line = stdin.readLine()) != null) {
    System.out.println(line);
}

但是代码总是挂在 readLine() 上。

我试过使用

stdin.read();

相反,但那也挂起。 尝试将 cmd 修改为

cmd = "perl /var/tmp/myscript";

还有

cmd = {"perl","/var/tmp/myscript"};

但这也挂起。 尝试在单独的线程中读取标准输入。尝试在不同的线程中读取 stdin 和 stderr。仍然没有运气。

我知道这里有很多问题处理 Process.waitFor() 由于未读取流而挂起,以及 BufferedReader.read() 挂起,尝试了所有建议的解决方案,仍然没有运气.

当然,运行在 CLI 本身上运行相同的脚本会将输出写入标准输出(控制台)并以退出代码 0 存在。 我正在 运行Centos 6.6 上。

我们将不胜感激。

我假设当直接从命令行 运行 时,脚本 运行 完成,产生预期的输出,并干净地终止。如果没有,请先修复您的脚本。

readLine() 调用挂起几乎肯定意味着既没有遇到行终止符也没有遇到文件结尾。换句话说,方法被阻塞等待脚本。也许脚本在条件下根本不产生任何输出,但不会终止。例如,如果它希望在继续之前从它自己的标准输入读取数据,则可能会发生这种情况。如果它在输出到其 stderr 时被阻止,也可能会发生这种情况。

在一般情况下,您必须通过 getInputstream() 和 [=14= 提供的 InputStream 并行读取 Process 的标准输出及其标准错误].您还应该通过向 getOutputStream() 提供所需的标准输入数据(也与读数并行)或关闭它来处理 OutputStream 提供的数据。如果您正在 运行ning 的特定进程不向这些流发送数据,并且您通常 应该 关闭 ProcessOutputStream 当您没有更多数据时。即使您不关心从中读取的内容,您也需要读取这两个 InputStreams,因为如果您不这样做,进程可能会阻塞或无法终止。要做到这一点很棘手,但对于特定情况来说比编写通用支持要容易得多。无论如何,还有 ProcessBuilder,它在某种程度上朝着更简单的通用接口迈进了一步。

尝试像这样使用 ProcessBuilder

String cmd = "/var/tmp/./myscript";

ProcessBuilder perlProcessBuilder = new ProcessBuilder(cmd);
perlProcessBuilder.redirectOutput(ProcessBuilder.Redirect.PIPE);
Process process = perlProcessBuilder.start();

stdin = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while((line = stdin.readLine()) != null) {
    System.out.println(line);
}

来自 ProcessBuilder javadoc (link)

public ProcessBuilder redirectOutput(ProcessBuilder.Redirect destination)

Sets this process builder's standard output destination. Subprocesses subsequently started by this object's start() method send their standard output to this destination.

If the destination is Redirect.PIPE (the initial value), then the standard output of a subprocess can be read using the input stream returned by Process.getInputStream(). If the destination is set to any other value, then Process.getInputStream() will return a null input stream.

Parameters:

destination - the new standard output destination

Returns:

this process builder

Throws:

IllegalArgumentException - if the redirect does not correspond to a valid destination of data, that is, has type READ

Since:

1.7