Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

piping output of ProcessBuilder to another ProcessBuilder

Is it possible to pass the output of one process created by ProcessBuilder to another process created by another ProcessBuilder? For example, if I'm trying to execute this shell command:

ls | grep build.xml

how should I do it with ProcessBuilder?

as @erdinc suggested, I tried this:

Process process = Runtime.getRuntime().exec("ls");
InputStream is = process.getInputStream();
byte[] buf = new byte[1000];
is.read(buf);
String parameter = new String(buf);
System.out.println("grep build " + parameter);

Process proc2 = Runtime.getRuntime().exec("grep build " + parameter);
InputStream is2 = proc2.getInputStream();
byte[] buf2 = new byte[1000];
is2.read(buf2);
String result = new String(buf2);
System.out.println("proc2 result: " + result);

but it produces different result compare to when I run the script directly in the shell. Where did I do wrong?

Solved: Please see Philipp Wendler solution

like image 918
ndriks Avatar asked Jan 05 '12 20:01

ndriks


People also ask

What connect the output of one process to the input of a second?

Pipe is used to combine two or more commands, and in this, the output of one command acts as input to another command, and this command's output may act as input to the next command and so on. It can also be visualized as a temporary connection between two or more commands/ programs/ processes.

How do I change the working directory in ProcessBuilder?

ProcessBuilder. directory(File directory) method sets this process builder's working directory. Subprocesses subsequently started by this object's start() method will use this as their working directory.

What is ProcessBuilder directory?

ProcessBuilder Class directory() method directory() method is used to return the working directory of this process builder. If it returns null to indicate the current working directory of the current process so the name of the directory will be assigned by using system property "user. dir" assign.

Is process Builder thread safe?

The ProcessBuilder Class Note that ProcessBuilder is not a synchronized class; hence, if it is not synchronized explicitly, it not thread safe to access the instance of this class through multiple threads.


1 Answers

The problem with the solution you have is that it reads only the first 1000 bytes from the output of ls and passes them to grep. As you don't know the amount of output from ls before, you need to read it iteratively until it is exhausted.

Here is a solution using BufferedReader, which will send each line of output to grep:

Process lsProcess = Runtime.getRuntime().exec("ls");
BufferedReader lsOutput = new BufferedReader(new InputStreamReader(lsProcess.getInputStream()));
Process grepProcess = Runtime.getRuntime().exec("grep build.xml");
BufferedWriter grepInput = new BufferedWriter(new OutputStreamWriter(grepProcess.getOutputStream()));

String line;
// read each line from ls until there are no more
while ((line = lsOutput.readLine()) != null) {
    // and send them to grep
    grepInput.write(line);
    grepInput.newLine();
}

// send end-of-file signal to grep so it will terminate itself
grepInput.close();

Of course you need to add the appropriate error-handling here. You can omit the Reader and Writer and pass byte[] arrays directly from the input to the output stream if this solution is too slow.

However, a much better solution would be not to use ls and grep to look for a file in the filesystem, but to use the appropriate Java API. For example if you create a File object for the directory you are interested in, you can use the various listFiles methods on it to list all files in this directory. This method is much easier, portable, less error-prone and probably faster.

like image 185
Philipp Wendler Avatar answered Sep 23 '22 10:09

Philipp Wendler