Java Exec() Does Not Return Expected Result of Pipes' Connected Commands

Java exec() does not return expected result of pipes' connected commands

Still didn't found proper solution to execute piped commands with Runtime.exec, but found a workaround. I've simply wrote these scripts to separate bash files. Then Runtime.exec calls these bash scripts and gets expected result.

Problem with run DOS command in Java

The angle brackets are redirection operators: <inputfile.txt causes the input to be read in from inputfile.txt instead of the keyboard, >outputfile.txt causes the output to be written to outputfile.txt instead of the screen. This facility is provided by the shell, however when invoking your program with the Java runtime the shell is not present. Invoke via the shell, like this:

Runtime.getRuntime().exec("cmd /c crf_test.exe model <inputfile.txt> outputfile.txt");

...or redirect input and output using facilities provided by Java; see e.g. this question.

How to make pipes work with Runtime.exec()?

Write a script, and execute the script instead of separate commands.

Pipe is a part of the shell, so you can also do something like this:

String[] cmd = {
"/bin/sh",
"-c",
"ls /etc | grep release"
};

Process p = Runtime.getRuntime().exec(cmd);

Capturing stdout when calling Runtime.exec

You need to capture both the std out and std err in the process. You can then write std out to a file/mail or similar.

See this article for more info, and in particular note the StreamGobbler mechanism that captures stdout/err in separate threads. This is essential to prevent blocking and is the source of numerous errors if you don't do it properly!

Run linux command through java.

Here's what you need to do:

String command = "nm -l file1.o > file1.txt";
Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", command});

The following "simple answer" WON'T WORK :

String command = "/bin/sh -c 'nm -l file1.o > file1.txt'";
Process p = Runtime.getRuntime().exec(command);

because the exec(String) method splits its the string naively using whitespace as the separator and ignoring any quoting. So the above example is equivalent to supplying the following command / argument list.

new String[]{"/bin/sh", "-c", "'nm", "-l", "file1.o", ">", "file1.txt'"};

Java process.waitFor() does not return

xcopy probably just happens to produce more output than move, filling up the out-buffer and blocking until it is flushed. The default behavior in Java is to pipe the subprocess's stdout/stderr into InputStreams that you are then required to read programmatically lest the subprocess's buffers overflow.

If the latter is the case, the solution is simple, and in fact you should do that anyway: use ProcessBuilder to prepare the system call and call inheritIO on it. This will reuse your parent process`s stdin and stdout for the subprocess.

A side note, xcopy is a regular .exe file and doesn't need wrapping into cmd.exe /c.

Java getRuntime Exec

Your Java process and your script are deadlocked waiting on each other: you are waiting for the process to exit, the process is waiting for you to read the output.

It happens to work for ls -alF and other commands with small outputs because they all fit in the pipe's buffer (64kib on my system).

Just move the p.waitFor() below the while loop, and you'll have more luck:

private String executeCommand(String command) {     
StringBuilder output = new StringBuilder();
BufferedReader reader = null;
Process p;
try {
p = Runtime.getRuntime().exec(command);
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
p.waitFor();

} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}

If you additionally want this to work correctly with values containing spaces and certain other characters, you have to:

  1. Quote "${args[0]}" in your script.
  2. Rewrite your executeCommand to use Runtime.exec(String[]) instead of Runtime.exec(String).


Related Topics



Leave a reply



Submit