Reputation: 3717
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?
Upvotes: 5
Views: 9542
Reputation: 11
Not sure if this can help, but I just had to check is another instance of my app was running in Linux so I implemented this which can return the count or the PID of the other instance (so I can bring to front and halt loading the new instance).
public long checkIsAlreadyRunning(){
//Check if app is already running
long lngCountOfInstances = 0; //Use this to hold how many already running
String strProcessName = "AG2_GetData";
//If it is required to also capture app running from within NetBeans, remove the .jar
so("ps -ef|grep " + strProcessName);
try{
long lngPid = ProcessHandle.current().pid();//PID of this instance of the application
long lngPidOfRunning = 0; //Holder for PID of already running instance
System.out.println(lngPid+""); //Only for verification
Runtime rt = Runtime.getRuntime();
String[] cmd = {"/bin/sh", "-c", "ps -ef|grep " + strProcessName };
Process proc = rt.exec(cmd);
delay_ms(2);//found I needed small delay to ensure buffer was ready
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String strLineIn;
StringBuilder strOutput = new StringBuilder();
String strProcessId = "";
while ((strLineIn = reader.readLine()) != null) {
if(!strLineIn.contains("grep") && !strLineIn.contains(String.valueOf(lngPid))) {//ignore is PID is current, or line contais grep
strOutput.append(strLineIn + "\r\n");//Only here for debuging
lngCountOfInstances++;
}
}
reader.close(); //always close the reader
String strReturn = removeDuplicates(strOutput.toString()," "); // remove duplicate spaces frm reteun
String[] strArray = strReturn.split(" ");
if(strArray.length>2){lngPidOfRunning = isLong(strArray[1]);}//Aray index 1 will be PID, isLong checks if valid long and if yes, retunrs long, esle 0;
System.out.println(lngPidOfRunning + " --> " + strReturn); //Only here for debuging
}
catch(Exception ex){
ex.printStackTrace();
err(ex.getMessage(), ex); //remove this, I use function to log messages and stacktraces to file
}
//return lngPidOfrunning; //Use this is you would like to use the PID to bring running instance to front
return lngCountOfInstances; //use this if you just want to get count of running instances
}
Upvotes: 0
Reputation: 301
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.
Upvotes: 1
Reputation: 98526
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"});
Upvotes: 4
Reputation: 11553
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\""
Upvotes: 2
Reputation: 6289
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
.
Upvotes: 5