AKS
AKS

Reputation: 220

Error while running linux command through Runtime.getRuntime().exec

I am trying to run following command in my Java program

Runtime.getRuntime().exec("ls -lrt service/logs/post/level2.log | awk '{print $9}'");
or
Runtime.getRuntime().exec("ls -lrt service/logs/post/level2* | awk '{print $9}'");

it gives me following error

ls: 0653-341 The file | does not exist.
ls: 0653-341 The file awk does not exist.
ls: 0653-341 The file '{print does not exist.
ls: 0653-341 The file $9}' does not exist.

Kindly help me

Upvotes: 1

Views: 2494

Answers (1)

Andrzej Doyle
Andrzej Doyle

Reputation: 103847

Pipes are a shell-based construct, not actual runnable commands. There are two options to do this as I see it:

  1. Do the piping yourself within Java. Invoke the ls command first, get a handle to its OutputStream and then invoke awk connecting the first Process's output to the second Process' input stream.
  2. Invoke the bash shell directly from Java, passing in the entire command as an argument to bash's -c parameter. That way all the piping is done within the single process.

As for the token-based errors, you should be invoking these commands with an array of strings; each element represents a token of the command line. So try, for example:

Runtime.getRuntime().exec(new String[] { "ls", "-lrt", "service/logs/post/level2.log" });

in order to invoke the ls command. I don't think this is strictly necessary in this case, but it will be for the awk command, since Java doesn't know anything about shell-specific quoting rules, so by default tokenises a single-string input on the space character. That's why your awk script was being split in two.


Edit (in response to comments): In the first option, I meant simply that you're able to pipe the output between the two processes yourself, in Java.

Imagine if you've created a process as so:

Process ls = Runtime.getRuntime().exec("ls -lrt service/logs/post/level2.log");

Now, this process will run and generate some output (which we know is going to be a line describing that file). We can get the stream for this output like so:

InputStream lsOut = ls.getInputStream();

Now, we want to run that awk process:

Process awk = Runtime.getRuntime().exec(new String[] { "awk", "{print $9}"});

The awk process of course will sit there are the moment waiting for input, since it knows it's going to be reading from stdin. So, we grab the input stream that it's going to be using:

OutputStream awkIn = awk.getOutputStream();

Now, the piping bit - we read the output of the ls command and pass it into the input for awk:

// TODO add buffering, error handling, probably run this in a separate thread
int datum = lsOut.read();
while (datum != -1)
{
    awkIn.write(datum);
    datum = lsOut.read();
}

This reads the output of ls (byte-by-byte for simplicity, using byte array buffers would be much faster but I'm trying to illustrate the concept simply) and writes it to the input of awk.

Then it's just a matter of reading the output from the awk process and dealing with it as you see fit.

Upvotes: 9

Related Questions