Search code examples
javashellprocessruntimeprocessbuilder

how to execute command "ps -eaf | grep myprocess" in java


I googled and checked the SO if there is any code to find PID of any other process. There is a solution to create a shell script with the command "ps -eaf | grep myprocess" in it and executing that script from java.

But I want to execute using java ProcessBuilder or Runtime methods. Below is the code that I have tried which is not giving me null as output.

import java.io.*;

public class TestShellCommand {

    public static void main(String args[]) {
        Process p = null;
        String command = "ps -ef | grep myProcess";
        try {
            // p = new ProcessBuilder(command).start();
            p = Runtime.getRuntime().exec(command);
            BufferedReader br[] = new BufferedReader[2];
            br[1] = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            br[0] = new BufferedReader(new InputStreamReader(p.getInputStream()));

            String line = null;
            if(br[0].readLine() == null){
                System.out.println("The input stream is null.");
            }
            while ((line = br[0].readLine()) != null) {
                System.out.println(line);
            }

            try {
                br[0].close();
            } catch (Exception a) {
                a.printStackTrace();
            }
            try {
                br[1].close();
            } catch (Exception a) {
                a.printStackTrace();
            }
        } catch (Exception grrr) {
            grrr.printStackTrace();
        } finally {
            try {
                closeStreams(p);
                p.destroy();
            } catch (Exception r) {
                r.printStackTrace();
            }
        }
    }

    static void closeStreams(Process p) throws IOException {
        p.getInputStream().close();
        p.getOutputStream().close();
        p.getErrorStream().close();
    }
}

The output for the command is :

java TestShellCommand
The input stream is null.
{sdc@ip-172-31-32-49}[26] echo $?
0

Please let me know if there is any error in my code as when I search manually from shell i do get the expected output as below:

ps -ef | grep myProcess
root       7433      1  0 10:33 ?        00:00:00 myProcess hello
sdc       19894  14130  0 11:24 pts/7    00:00:00 grep myProcess

[UPDATED CODE - Without the grep command]

import java.io.*;

public class TestShellCommand {

    public static void main(String args[]) {
        Process p = null;
        String [] command = {"ps", "-eaf"};
        try {
            p = Runtime.getRuntime().exec(command);
            BufferedReader br[] = new BufferedReader[2];
            br[1] = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            br[0] = new BufferedReader(new InputStreamReader(p.getInputStream()));

            String line = null;
            if(br[0].readLine() == null){
                System.out.println("The input stream is null.");
            }
            while ((line = br[0].readLine()) != null) {
                System.out.println(line);
            }

            // Then code to find by process name by using string methods ...

            try {
                br[0].close();
            } catch (Exception a) {
                a.printStackTrace();
            }
            try {
                br[1].close();
            } catch (Exception a) {
                a.printStackTrace();
            }
        } catch (Exception grrr) {
            grrr.printStackTrace();
        } finally {
            try {
                closeStreams(p);
                p.destroy();
            } catch (Exception r) {
                r.printStackTrace();
            }
        }
    }

    static void closeStreams(Process p) throws IOException {
        p.getInputStream().close();
        p.getOutputStream().close();
        p.getErrorStream().close();
    }
}

I have added the code that is working, when I am passing command as:

  1. new String[]{"/bin/sh","-c", "ps -eaf | grep "+ "myProcess" +" | grep -v grep"} - Empty response.
  2. new String[] {"ps", "-eaf", "grep -m 1 myProcess", "awk -F ' ' '{print $2}' "} - Empty response.

Thanks in advance for any leads.


Solution

  • As @Slimo answer indicates you must launch a shell to execute a shell command (the pipe), and read the error stream to determine what may have gone wrong.

    Launching subprocess without using waitFor() or consuming stdout and stderr at SAME time can lead to issues, use file redirect or as in this example merge stderr -> stdout and read one stream only:

    String procname = "myProcess";
    String[] cmd = new String[]{"bash","-c", "ps -eaf | grep "+procname+" | grep -v grep"}
    ProcessBuilder pb = new ProcessBuilder(cmd);
    pb.redirectErrorStream(true);
    Process process = pb.start();
    process.getInputStream().transferTo(System.out);
    int rc = process.waitFor();
    if (rc != 0)
        throw new RuntimeException("Failed rc="+rc+" cmd="+Arrays.toString(cmd));
        
    

    In later JDK you don't need ProcessBuilder, you may find all the process attributes in the data-structures returned by ProcessHandle:

    ProcessHandle.allProcesses()
        .filter(ph -> ph.info().command().isPresent() && ph.info().command().get().contains(procname))
        .forEach(ph -> System.out.println("PID: "+ph.pid()+" command: "+ph.info().command()))