9

I am using the following code to get the details of all process running in the system:

Process p = Runtime.getRuntime().exec("ps aux");
BufferedReader stdInput = new BufferedReader(new 
             InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new 
             InputStreamReader(p.getErrorStream()));

I want to filter ps aux down with the pipe symbol so I use this:

Process p = Runtime.getRuntime().exec("ps aux | grep java");

It goes to the ErrorStream. Later I noticed the Pipe Symbol (|) is used as Bitwise inclusive OR operator in Java. So I used backslash in front of pipe symbol as shown below:

Process p = Runtime.getRuntime().exec("ps aux \\| grep java"); 

But again it goes to the ErrorStream. How can I run ps aux | grep java through exec in Java?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Vinesh
  • 933
  • 2
  • 7
  • 22
  • Just to clarify, the bitwise OR operator `|` is not interpreted within strings so you shouldn't need to escape it. – Nate W. Aug 29 '11 at 05:51

4 Answers4

16

Well, if you want to use pipes in the Process you exec, then you need to start a shell like bash, and give ps and grep on the command line to that shell:

bash -c "echo $PATH"

Try this to understand what I mean, then use this:

bash -c "ps axu | grep PATTERN"

to understand how you need to set up your java.runtime.Process.

I did not try it but I assume this:

Process p = Runtime.getRuntime().exec(new String[] { "bash", "-c", "ps axu | grep PATTERN" });

Hope that helps ;D

Angel O'Sphere
  • 2,642
  • 20
  • 18
  • That was not working for me... After reading [this](http://stackoverflow.com/questions/9375711/more-elegant-ps-aux-grep-v-grep), I finally decide to use pgrep instead of grep – boly38 Mar 31 '15 at 09:15
5

The pipe is a shell feature - you're not using a shell, you're exec'ing a process (ps).

But really, why would you want to do this? What you're saying is:

"execute ps, then pipe its output to another program (grep) and have it extract what I need"

You just need to extract what you want from the output of ps. Use a Matcher and only pay attention to the lines that include java from your InputStream

http://download.oracle.com/javase/6/docs/api/java/util/regex/Matcher.html

Brian Roach
  • 76,169
  • 12
  • 136
  • 161
  • Thanks for your reply. When i use Runtime.getRuntime().exec("ps aux") it takes time to process all lines from InputStream. So i thought Runtime.getRuntime().exec("ps aux | grep java") will simply my work. If i go with Matcher again it will take time to process lines. Is there any other way to use pipe? – Vinesh Aug 29 '11 at 06:03
  • 2
    It really shouldn't take much more time for you to process the lines with a `Matcher` than a shell having to exec another process and pipe the output of `ps` to it. That being said ... I *think* you could exec a shell such as `/bin/bash -c ps aux |grep java` – Brian Roach Aug 29 '11 at 06:10
5
  1. You need to separate the command from its arguments when calling exec, eg .exec(new String[] { "ps", "aux" }) (not exec("ps aux")). When you need to pass arguments, you need to invoke the String[] version - the first element of the String[] is the command, the rest are the arguments.

  2. You need to send the contents of the output stream of the first command to the input stream of the second command. I used Apache commons IOUtils to do this with ease.

  3. You must close the input stream of the grep call, otherwise it will hang waiting for the end of input.

With these changes in place, this code does what you want:

import org.apache.commons.io.IOUtils;

public static void main(String[] args) throws Exception
{
    Process p1 = Runtime.getRuntime().exec(new String[] { "ps", "aux" });
    InputStream input = p1.getInputStream();
    Process p2 = Runtime.getRuntime().exec(new String[] { "grep", "java" });
    OutputStream output = p2.getOutputStream();
    IOUtils.copy(input, output);
    output.close(); // signals grep to finish
    List<String> result = IOUtils.readLines(p2.getInputStream());
    System.out.println(result);
}
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 2
    Is that a deadlock hazard when single-threaded? Could use `PumpStreamHandler` from commons-exec. – clstrfsck Aug 29 '11 at 06:34
  • Fair comment. I was trying to keep this as simple as possible to illustrate to important bits. Caution: May deadlock in single-thread environments. – Bohemian Aug 29 '11 at 07:36
  • I wish the JDK provided the equivalent of `IOUtils.copy`. This is where other languages are more appealing for some programs. – Sridhar Sarnobat Aug 20 '22 at 19:36
0

Sorry I do not know how to correctly pipe results from one command to another, but if all you want is the Java process, the JDK comes with a program called jps that does exactly this. Try this:

jps -l
Nate W.
  • 9,141
  • 6
  • 43
  • 65
  • Thanks for the reply. I tried the command, it produces the list that contains PID, Process Name. What i am looking to get PID %CPU %MEM VSZ RSS TTY & COMMAND. – Vinesh Aug 29 '11 at 06:10