Java - how to check whether another (non-Java) pro

2020-04-08 14:16发布

问题:

I'm having some weird problems with this.

We are using Xvfb virtual desktop manager and want to make sure it's running before I continue. Using pure shell, I could do this easily:

    ps -ef | grep Xvfb | grep -v grep

And that gives me exactly what I need, a single line containing information about the Xvfb proc. Next, I want to incorporate this into my Java program and parse the results and store the PID of the running Xvfb process. So I am trying this:

    String line;
    try {
      Process p = Runtime.getRuntime().exec("ps -ef | grep Xvfb | grep -v grep");
      BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
      while ((line = input.readLine()) != null)
      {
        System.out.println(line);
      }
    } catch (Exception err) {
      System.out.println(err);
    }

The bizarre thing is that if I use "ps -ef", I get a huge list of processes dumped to my console when I run my app. But if I use | grep to narrow the list of processes returned, I get zero results. input.readLine() gets null every time.

I have also tried:

    ps -ef | grep Xvfb | grep -v grep | awk {'print $2'}

To just grab the process id. Also, no luck.

Has anyone else experienced this or know what I'm doing wrong?

回答1:

You're trying to use the "|" which is a pipe function that is particular to the shell, therefore you cannot do it in the java process. You could just try getting the process ID by using pidof Xvfb.



回答2:

Maybe Runtime.getRuntime().exec() tries to execute the program as it is in the argument. That is, it runs the program ps with arguments -ef, |, grep, etc. And so, the program fails because it does not understand what's going on.

If you need to run piped commands, you should call the shell explicitly:

Runtime.getRuntime().exec(new String[] {"sh", "-c", "ps -ef | grep Xvfb | grep -v grep"});


回答3:

When you execute your command string directly you do not get a shell and it is the shell which handles the pipes. So, you would execute something like "/bin/sh -e \"ps -ef | grep Xvfb | grep -v grep\""



回答4:

There's a lot of ways of doing this. You can use java.lang.ProcessBuilder and "pgrep" to get the process id (PID) with something like: pgrep -fl java | awk {'print $1'}. Or, if you are running under Linux, you can query the /proc directory.

I know, this seems horrible, and non portable, and even poorly implemented, I agree. But because Java actually runs in a VM, for some absurd reason that I can't really figure out after more then 15 years working the JDK, is why it isn't possible to see things outside the JVM space, it's really ridiculous if you think about it. You can do everything else, even fork and join child processes (those were an horrible way of multitasking when the world didn't know about threads or pthreads, what a hell! what's going on with Java?! :).

This will give an immense discussion I know, but anyways, there's a very good API that I already used in my projects and it's stable enough (it's OSS so you still need to stress test every version you use before really trusting the API): https://github.com/jezhumble/javasysmon

JavaDoc: http://jezhumble.github.io/javasysmon/, search for the class com.jezhumble.javasysmon.OsProcess, she will do the trick. Hope it helped, best of luck.