I have a code which calls a specific command within the Mac Terminal, I then use a buffered reader to read and print the result from the terminal. I have been doing this with a couple of commands, only problem is I am now in need of using the command ps -ef | grep google (program name is of course different, but for now I'll just use google). The only issue by using this command is the fact that the buffered reader doesn't seem to be able to read and print the outcome. I am 100% sure that the actual command works, as I have tried to run the command in the terminal alone. I am not exactly sure why this problem is all of a sudden happening now.
The command is used to check whether a specific application is running and where it has been launched from.
The code I am using is the one below here.
try {
String procss;
Process pRun = Runtime.getRuntime().exec("ps -ef | grep google");
BufferedReader input = new BufferedReader(new InputStreamReader(pRun.getInputStream()));
while ((procss = input.readLine()) != null) {
if(!procss.contains("Contents"))
{
//Do something
}
}
input.close();
} catch (Exception err) {
err.printStackTrace();
}
To give an example of a command where it has worked without any problem, I have also just included a working code below. To show how I would actually like it to work, but just with the right command ps -ef | grep google instead.
try {
String procss;
Process pRun = Runtime.getRuntime().exec("top -F -R -o cpu");
BufferedReader input = new BufferedReader(new InputStreamReader(pRun.getInputStream()));
while ((procss = input.readLine()) != null) {
if(!procss.contains("testApplication"))
{
//Do something
}
}
input.close();
} catch (Exception err) {
err.printStackTrace();
}
I am not sure whether I need to use another method of reading the outcome or what I have to do for my code to actually work again.
Related
I have the following problem which seems to be caused by the "docker pull" in my shell script, as the pull works concurrently
#!/bin/bash
#VARIABLES
NAME="my-app"
IMAGE="my-image:latest"
#DOCKER
docker stop $NAME
docker rm $NAME
docker pull -q $IMAGE
docker run --name $NAME -d -p 1234:8080 --log-opt fluentd-address=localhost:2233 $IMAGE
Running the script through the terminal works just fine everything works as expected. But when I run it with the Java's ProcessBuilder the script exits much quicker and it seems that it skips the "docker pull" step. As i am not a Java developer and I am not very well familiar with the Language I have the feeling that is something related to the multi-concurrent nature of the docker pull command and the way how the Java Process Builder executes the shell script
The Java class that runs the shell script is this
try {
Collection<Task> tasks = taskService.getProjectTasksByProjectKey(projectId);
Task findTask = findTaskByTaskId(tasks, taskId);
if (findTask.getTaskId() != null) {
ProcessBuilder pb = new ProcessBuilder(findTask.getCmdPath());
Process process = pb.start();
String output;
try (InputStream in = process.getInputStream();
InputStream err = process.getErrorStream();
OutputStream closeOnly = process.getOutputStream()) {
while (process.isAlive()) {
long skipped = in.skip(in.available())
+ err.skip(err.available());
if(skipped == 0L) {
process.waitFor(5L, TimeUnit.MILLISECONDS);
}
}
output = loadStream(in);
} finally {
process.destroy();
}
// String error = loadStream(process.getErrorStream());
// int rc = process.waitFor();
// log.debug("exit code ->>> " + rc);
// StringBuilder output = new StringBuilder();
// BufferedReader reader = new BufferedReader(
// new InputStreamReader(process.getInputStream()));
//
// String line;
//
// while ((line = reader.readLine()) != null) {
// output.append(line + "\n");
// }
//
// int exitVal = process.waitFor();
// if (exitVal == 0) {
// System.out.println(output);
//
// return output.toString();
// } else {
// //abnormal...
// }
return output;
}
else {
throw new InvalidTaskModelException(taskId);
}
} catch (InvalidModelException e) {
throw new InvalidModelException(projectId);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String loadStream(InputStream s) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(s));
StringBuilder sb = new StringBuilder();
String line;
while((line=br.readLine()) != null)
sb.append(line).append("\n");
return sb.toString();
}
The commented lines are different ways I tried to do it.
If anyone encountered a similar problem any help would be much appreciated!
It is good that you already take care for the processes' STDOUT and STDIN. But rather than skipping copy them to System.out so you can see what is going on. I suspect something is not going as per your expectations.
Looking at the bash script you posted and the fact you are trying to run several processes: Is it possible your java code is running the bash script line by line? Be aware your java program it is not a BASH interpreter, so e.g. variable substitution should not work.
why you can not run each command in thread and joins them so that unless therad 1 is not completed . next thread can not start .
also please add command to verify image is downloaded successfully
docker pull -q $IMAGE
docker images | grep $IMAGE
docker run --name $NAME -d -p 1234:8080 --log-opt fluentd-address=localhost:2233 $IMAGE
i am guessing there are 2 possiblities are here
Check local directory persmission if possible give 755 permission to
it .
Java process itself is not able to execute docker command due
to permission issue, run process as sudo user.
I've been trying to make an app to act as a ssh / scp client to make transferring files easier from my laptop to my desktop and currently I have been able to get the output of a ls command and get the file tree for the host and remote user, however this requires input in the terminal I am running the app with.
Is it possible to be able to embed a terminal window into a gui as I have went about making an interpreter however things like tab completion and running, for example, python3 don't work. I am also hoping to have full use of a terminal and be able to run commands like vim rather than just print the output of commands which is what I currently have.
My code for executing the commands is:
public void processCmd(String command) {
if (command.equals("exit")) {
System.exit(0);
} else if (command != null && !command.isEmpty()) {
execCommand(command);
}
}
public void execCommand(String input) {
String result = null;
try {
Runtime r = Runtime.getRuntime();
Process p = r.exec(input);
BufferedReader in =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
result += inputLine;
}
in.close();
} catch (IOException e) {
System.out.println("Error");
}
}
The main problem is that when anything like python or vim is run, the app will hang and not do anything, python won't even show up in terminal, however, if I run vim, it will change the terminal screen (not in the app) to mostly vim but without the bottom bar.
So essentially, I am trying to run the command "/dir/command -arg" to change the LED color on a USB device in Java. I am using Ubuntu 10.04. When I run the command from the terminal, it works just fine.
However, I tried every iteration of Runtime.exec() that I could find and none of them seem to work. I then created a script with the following contents:
#!/bin/bash
echo "hello"
/dir/command -arg
when I run this from a terminal it works just fine. However when I run
#Override
public void run() {
String[] lookupCmd = {"/bin/sh","-c", "sh /dir/script.sh"};
try {
Runtime runtime = Runtime.getRuntime();
Process lookupProc = runtime.exec(lookupCmd);
lookupProc.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(lookupProc.getInputStream()));
String line = reader.readLine();
while (line != null) {
id.add(line);
System.out.println(line);
line = reader.readLine();
}
} catch (Exception e) {
System.err.println(e);
}
}
"hello" print but nothing else. There is no error.
My other command should not yield any output, but simply change the color of an LED. However when I run it with the same command but a different arg which yields an ouput, it still only prints "hello".
I also made sure that my user has permissions to the /dev folder with the usb device.
I wasn't running the error stream, so I've added that.
After that I realized I was missing an environment variable, so added:
String[] envar = {"VAR=path"}
and called:
runtime.exec(lookupCmd, envar);
Works great now.
I have written a code to check whether HSQL, JBoss, Radius (AAA sever) and MySQL is running or not.The code is written in an inifinte while loop to continuously monitor.Now I tested that if this service (let's say hsql) is running then /bin/bash -c ps -ef | grep 'hsql' | wc -l will return 3 when this is passed as an argument in Runtime.exec() method. Now I have come to know that the inputstream or errstream of the forked process must not be overflowed. Otherwise it'll cause deadlock.
Keeping that in mind I have written this code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;
public class MonitorHsqlJBossRadius {
public static void main(String[] args) {
String hsqlCmd[] = {"/bin/bash","-c","ps -ef | grep 'hsql' | wc -l "};
String jbossCommand[] = {"/bin/sh","-c","ps -ef | grep 'jboss' | wc -l"};
String radiusCommand[] = {"/bin/sh","-c","ps -ef | grep 'radius' | wc -l"};
String mySqlCommand[] = {"/bin/sh","-c","/etc/init.d/mysqld status"};
String line = null;
String mobNo = "(obscured)";
Process process = null;
Runtime runtime = Runtime.getRuntime();
BufferedReader reader = null;
SendSMS sender = new SendSMS();
boolean sendMsgHsql = false;
boolean sendMsgJBoss = false;
boolean sendMsgRadius = false;
int itr = 1;
while(true)
{
try
{
process = runtime.exec(hsqlCmd);
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while((line=reader.readLine())!=null)
{
if (!line.equals("3"))
sendMsgHsql = true;
}
process.waitFor();
if (sendMsgHsql)
{
//sender.sendSMS("HSQL is not running "+(new Date().toString()), mobNo,1,itr);
System.out.println("HSQL is not running "+itr);
}
else
System.out.println("HSQL is running "+itr);
sendMsgHsql = false;
process = runtime.exec(jbossCommand);
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while((line=reader.readLine())!=null)
{
if (!line.equals("3"))
sendMsgJBoss = true;
}
process.waitFor();
if (sendMsgJBoss)
{
//sender.sendSMS("JBoss is not running "+(new Date().toString()), mobNo,2,itr);
System.out.println("JBoss is not running "+itr);
}
else
System.out.println("JBoss is running "+itr);
sendMsgJBoss = false;
process = runtime.exec(radiusCommand);
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while((line=reader.readLine())!=null)
{
if(!line.equals("3"))
sendMsgRadius = true;
}
process.waitFor();
if (sendMsgRadius)
{
//sender.sendSMS("Radius is not running "+(new Date().toString()), mobNo,3,itr);
System.out.println("Radius is not running "+itr);
}
else
System.out.println("Radius is running "+itr);
sendMsgRadius = false;
}
catch (IOException e) {
e.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
}
try
{
System.out.println("\n--------- "+itr+" ------------\n");
itr++;
Thread.sleep(1000*5);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
The output I'm expecting is as follows
HSQL is running/not running 1
JBoss is running/not running 1
MySQL is running/not running 1
-------------------1----------------
HSQL is running/not running 2
JBoss is running/not running 2
MySQL is running/not running 2
-------------------2----------------
and so on...
Howevere I'm not getting output like that. Sometimes HSQL's status message is not printed or sometimes JBoss status message is not printed. Even sometimes I get output like
------------------1----------------------
after this status messages are printed. All I'm trying to say is that seems to be some race condition or some synchronization problem.
Trying to determine whether a process is running by parsing the output of ps is usually not a good idea. The typical error is that grep processname matches (atleast) two processes: both processname and the grep-process itself.
The usual way of doing this is:
when starting the process, write the pid to a file
when checking the process, read the pid from file and see if it exists by sending it a signal
An even more robust and elegant way of doing it, is to let the process open a socket and checking if this is available, but in this case you wouldn't want to add code for this in your servers. However, the processes you want to check already listen to TCP-ports. I would write code that tried to connect to this port (typically port 80 for jboss, 3306 for mysql, 9001 for hsql) Radius is a bit more tricky as it uses UDP. You could try to perform an authentication, or you could look for specific characteristics with your particular radius-server.
I don't believe your code is hanging due to a race condition or synchronization at all. I don't have access to your server, so I can't run your code to be sure, but instead I suspect that the processes you are running are blocking because they are writing to their standard error and you are not reading from it.
It is possible to read from the standard error stream of a Process created by Runtime.getRuntime().exec(), but reading from this stream has to be done in a separate thread. Instead, I would recommend using a ProcessBuilder. In my opinion, the most significant benefit of a ProcessBuilder is that it can redirect the standard error of the process into the same stream as the standard output. This means you only have one stream to read from and there is no need for a separate thread.
I'll also note that you are opening various BufferedReaders but not closing them. I would recommend that you close them when you have finished with them.
Finally, I would recommend that you don't repeat virtually the same code three times. It should be possible to write a method that takes the command line to run as a String array parameter, runs the command line using a ProcessBuilder and returns whether a line 3 was among the output from that command.
I am attempting to get output of a shell / bash script, that is run from a JAVA program, although I am not having much luck, the code is as follows:
GetStats(winhostname);
public static String winhostname "cmd /c hostname";
public static void GetStats(String operation)
{
try
{
Process p=Runtime.getRuntime().exec(operation);
p.waitFor();
BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));
String line=reader.readLine();
while(line!=null)
{
System.out.println(line);
if (operation.equals("winhostname"))
{
winhostnamevalue = line;
}
line=reader.readLine();
}
}
catch(IOException e1) {}
catch(InterruptedException e2) {}
}
This works on Windows fine, so I changed the value of winhostname to "sh namecheck.sh" (which simply echos the hostname) and the shell script is located in the same directory as the java / class file. Although when run I get a blank result, not null, just blank.
Try /bin/sh. I do not sure that when you are running program from java it has all environment that you have when you are working with shell.
If it does not work try to run some command (e.g. pwd). But provide full path. Then, when it works try your command again and be sure that it can find your script. For the beginning use absolute path. Then move to relative path.
Good luck.