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

Consider the following code:

String commandf = "ls /etc | grep release"; try { // Execute the command and wait for it to complete Process child = Runtime.getRuntime().exec(commandf); child.waitFor(); // Print the first 16 bytes of its output InputStream i = child.getInputStream(); byte[] b = new byte[16]; i.read(b, 0, b.length); System.out.println(new String(b)); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } 

Program Output:

 /etc: adduser.co 

When I start from the shell, of course, it works as expected:

 poundifdef@parker:~/rabbit_test$ ls /etc | grep release lsb-release 

The Internet tells me that because the behavior of the pipes is not cross-platform, the brilliant minds that work in the Java Java factory cannot guarantee the operation of the pipes.

How can i do this?

I will not do all my parsing using Java constructors, not grep and sed , because if I want to change the language, I will have to re-write my syntax code in that language, which does not matter at all.

How can I get Java to redirect and redirect when invoking shell commands?

+78
java exec
May 8 '11 at 15:08
source share
3 answers

Write a script and execute the script instead of the individual commands.

The pipe is 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); 
+127
May 08 '11 at 15:20
source share

I ran into a similar problem on Linux, except that it was "ps -ef | grep someprocess".
At least with "ls" you have a language-independent (albeit slow) Java replacement. For example:.

 File f = new File("C:\\"); String[] files = f.listFiles(new File("/home/tihamer")); for (String file : files) { if (file.matches(.*some.*)) { System.out.println(file); } } 

With "ps" this is a little more complicated because Java doesn't seem to have an API for it.

I heard that Cigar could help us: https://support.hyperic.com/display/SIGAR/Home

The simplest solution, however (as indicated by Kaj) is to execute the piped command as a string array. Here is the complete code:

 try { String line; String[] cmd = { "/bin/sh", "-c", "ps -ef | grep export" }; Process p = Runtime.getRuntime().exec(cmd); BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); while ((line = in.readLine()) != null) { System.out.println(line); } in.close(); } catch (Exception ex) { ex.printStackTrace(); } 

As for why the String array works with pipe, while one row is not ... this is one of the mysteries of the universe (especially if you haven't read the source code). I suspect this is because when exec is given one line, it parses it first (in a way that we don't like). In contrast, when exec is given a string array, it simply passes it to the operating system without parsing it.

Actually, if we choose the time from a busy day and look at the source code ( http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Runtime.java # Runtime.exec% 28java.lang.String% 2Cjava.lang.String []% 2Cjava.io.File% 29 ), we find that this is exactly what happens:

 public Process [More ...] exec(String command, String[] envp, File dir) throws IOException { if (command.length() == 0) throw new IllegalArgumentException("Empty command"); StringTokenizer st = new StringTokenizer(command); String[] cmdarray = new String[st.countTokens()]; for (int i = 0; st.hasMoreTokens(); i++) cmdarray[i] = st.nextToken(); return exec(cmdarray, envp, dir); } 
+17
Oct. 15 '13 at 14:21
source share

Create a runtime to run each of the processes. Get an OutputStream from the first run time and copy it to an InputStream from the second.

+6
May 08 '11 at 15:11
source share



All Articles