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

孤街醉人 提交于 2019-12-12 06:08:51

问题


I'm trying to run a perl script from Java code and read it's output with the following code:

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);
}

But the code always hangs on the readLine().

I tried using

stdin.read();

Instead but that also hangs. tried modifying the cmd to

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

And also

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

But that also hangs. tried reading the stdin in separate thread. tried reading both stdin and stderr in separate threads. Still no luck.

I know there are many questions here dealing with Process.waitFor() hanging due to not reading the streams, as well as BufferedReader.read() hanging, tried all the suggested solutions, still no luck.

Of course, running the same script on the CLI itself writes output to the standard output (console) and exists with exit code 0. I'm running on Centos 6.6.

Any help will be appreciated.


回答1:


I presume that when run directly from the command line, the script runs to completion, producing the expected output, and terminates cleanly. If not, then fix your script first.

The readLine() invocation hanging almost surely means that neither a line terminator nor end-of-file is encountered. In other words, the method is blocked waiting for the script. Perhaps the script produces no output at all under the conditions, but does not terminate. This might happen, for instance, if it expects to read data from its own standard input before it proceeds. It might also happen if it is blocked on output to its stderr.

In the general case, you must read both a Process's stdout and its stderr, in parallel, via the InputStreams provided by getInputstream() and getErrorStream(). You should also handle the OutputStream provided by getOutputStream() by either feeding it the needed standard input data (also in parallel with the reading) or by closing it. You can substitute closing the process's streams for reading them if the particular process you are running does not emit data to those streams, and you normally should close the Process's OutputStream when you have no more data for it. You need to read the two InputStreams even if you don't care about what you read from them, as the process may block or fail to terminate if you do not. This is tricky to get right, but easier to do for specific cases than it is to write generalized support for. And anyway, there's ProcessBuilder, which goes some way toward an easier general-purpose interface.




回答2:


Try using ProcessBuilder like so:

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);
}

From the 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



来源:https://stackoverflow.com/questions/33920224/bufferedreader-read-hangs-when-running-a-perl-script-using-runtime-exec

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