rickygrimes
rickygrimes

Reputation: 2716

Java runtime getRuntime exec not returning desired results

I have the below code that is sorting contents of my file based on timestamp but it's not working. If I pass the unix command directly, ie cat /var/test/mylog/output.txt | sort -n, it works perfectly but it won't execute in my Java code.

private void writeResponseEntityToFile(List<String> response) throws IOException, InterruptedException {
    Path out = Paths.get("/var/log/logstream/output.txt");
    Files.write(out, response, Charset.defaultCharset());
    Process process = Runtime.getRuntime().exec("cat /var/test/mylog/output.txt | sort -n");
    process.waitFor();
}

Upvotes: 1

Views: 797

Answers (2)

DuncG
DuncG

Reputation: 15196

You cannot run a SHELL command from Java, you need either to run bash subprocess before cat | sort as indicated by @k314159 or change your command to regular executable (assuming sort is on your path):

sort -n /var/test/mylog/output.txt

Note: you must handle stdout + stderr streams before process.waitFor() as this can lead to the process freezing when the output of either stream is unread and exceeds the default buffer size. Streams are easier to control with ProcessBuilder, you can redirect to file(s), or merge stderr to stdout (thus avoiding need for background thread reader) as in this example:

ProcessBuilder pb = new ProcessBuilder(new String[]{"sort","-n", "/var/test/mylog/output.txt"});
pb.redirectErrorStream(true);
Process process = pb.start();
process.getInputStream().transferTo(System.out);
int rc = process.waitFor();
if (rc != 0)
    throw new RuntimeException("Sort failed rc="+rc);

Upvotes: 1

k314159
k314159

Reputation: 11266

This is because Runtime.exec executes the given file (cat) directly, without using the shell. When you type cat /var/test/mylog/output.txt | sort -n into the shell, it is the shell that does the piping, i.e. it creates a pipe, executes cat /var/test/mylog/output.txt sending its output to the pipe, and concurrently also executes sort -n, giving it the pipe output as its input. You can execute a shell command like that from Java's Runtime by executing bash or a similar shell. You should use the form of exec that takes an array of String, and pass the command bash as the first argument:

Process process = Runtime.getRuntime().exec(
    new String[]{"bash", "-c", "cat /var/test/mylog/output.txt | sort -n"});

The next thing to do is to think about what you want to do with the output of that command. Use Process.getInputStream() for that; e.g.

Process process = Runtime.getRuntime().exec(
    new String[]{"bash", "-c", "cat /var/test/mylog/output.txt | sort -n"});
if (process.waitFor() != 0) {
    System.err.println("Something went wrong")
} else {
    String output = new String(process.getInputStream().readAllBytes())
    ...
}

Upvotes: 1

Related Questions