0

I want to know which jars are loaded by all the different running JVM's.

If I type "lsof -p $PID | grep jar >> /somefile" from the bash/command, it works beautifully! (replacing $PID with an actual process id). However, I would like to be able to do this from within a Java program. I would expect the following code to work but no file gets written:

public static void printCustomCommand(){
    String[] pids = {"pidof java"};
    String s;

    try {
        Process pidProcess = Runtime.getRuntime().exec("pidof java");
        BufferedReader br = new BufferedReader(new InputStreamReader(pidProcess.getInputStream()));
        pids = br.readLine().split(" ");

        for (String pid : pids){
            String cmd = "lsof -p " + pid + " | grep jar >> /somepath/mydumpfile";
            Process p;
            p = Runtime.getRuntime().exec(cmd);
            System.out.println(p.waitFor());
        }

        //pids = new String(bo).split(" ");
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

When I print the p.waitFor() command, it returns a 1 always, meaning according to the API documentation "something is incorrect". http://docs.oracle.com/javase/6/docs/api/java/lang/Process.html#waitFor%28%29

Rens Groenveld
  • 960
  • 11
  • 28

2 Answers2

1

The issue is that Runtime.exec() does not understand shell concepts such as "|". Try this:

public static void printCustomCommand(){
    String[] pids = {"pidof java"};
    String s;

try {
    Process pidProcess = Runtime.getRuntime().exec("/bin/bash -c pidof java");
    BufferedReader br = new BufferedReader(new InputStreamReader(pidProcess.getInputStream()));
    pids = br.readLine().split(" ");

    for (String pid : pids){
        String cmd = "/bin/bash -c lsof -p " + pid + " | grep jar >> /somepath/mydumpfile";
        Process p;
        p = Runtime.getRuntime().exec(cmd);
        BufferedReader reader = 
        new BufferedReader(new InputStreamReader(p.getInputStream()));

    String line = "";
    while((line = reader.readLine()) != null) {
        System.out.print(line + "\n");
    }

    p.waitFor();  
    }

    //pids = new String(bo).split(" ");
} catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
}

The problem is that exec runs a binary directly without invoking the shell. The "|" character is only recognized by the shell. The "-c" tells the shell to run a single command, and passes the entire command as the single argument.

Devarsh Desai
  • 5,984
  • 3
  • 19
  • 21
  • Looks like I'm on the right path now with your answer. Thank you! I had to change the first exec command back to "pidof java" or otherwise I'd got a nullpointer at br.readLine().split(" "); Now although I do get a lot of jars back, the command returns a different result to me (more than only jars, i.e. opendir: permission denied). I'm quite new to Linux, but I'm guessing it has something to do with other users working on the same server maybe? – Rens Groenveld Jul 30 '14 at 07:30
  • What I mean with, I get different results is that I get different results in Java than in just a shell :) – Rens Groenveld Jul 30 '14 at 07:30
  • Resolved it, my final solution would be to create a String array instead of one String. It was in PeterMmm's suggestion and works very nice. – Rens Groenveld Jul 30 '14 at 09:48
1

Isn't that

Process pidProcess = Runtime.getRuntime().exec(new String[]{"pidof","java"});

?

And you cannot use pipes (|) in the exec method. The exec executes commands (executables) but pipes is part of the/a shell.

PeterMmm
  • 24,152
  • 13
  • 73
  • 111