Cannot launch shell script with arguments using Java ProcessBuilder - java

I am trying to execute a shell script with command line arguments using ProcessBuilder, this shell script inturn calls two other shell scripts that uses this argument. The first shell script runs fine, but when the second one is started it returns exit code 1.
ProcessBuilder snippet from Java Program:
//scenario - A string that holds a numerical value like 1 or 2 etc
String[] command2 = {"/bin/bash", "<path to shell script>/runTemporaryTestSuite.sh", scenario};
ProcessBuilder pb2 = new ProcessBuilder(command2);
Process p2 = pb2.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p2.getInputStream()));
String line;
//print - is an object ref of response.getWriter() //
print.println("Output of running "+Arrays.toString(command2)+" is: ");
while ((line = br.readLine()) != null) {
print.println(line);
}
try {
int exitValue = p2.waitFor();
print.println("<br><br>Exit Value of p2 is " + exitValue);
} catch (InterruptedException e) {
e.printStackTrace();
}
runTemporaryTestSuite.sh
#!/bin/bash
sh <path to script>/clearRegressionResult.sh (This runs fine)
sh <path to script>/startRegression.sh $1 (This is where the issue occurs)
startRegression.sh looks like:
SUITE_PATH="./"
java -DconfigPath=${SUITE_PATH}/config.xml -Dscenario=$1 -Dauto=true -jar test.jar
My output:
Output of running [/bin/bash, /runTemporaryTestSuite.sh, 29] is:
Exit Value of p2 is 1
Any help in resolving this is really appreciated.

In think the problem is not that you cannot launch shell script with arguments, I was curious and I did a test
public class Main {
public static void main(String[] args) throws IOException {
String[] command = {"/bin/bash", "test.sh", "Argument1"};
ProcessBuilder p = new ProcessBuilder(command);
Process p2 = p.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p2.getInputStream()));
String line;
System.out.println("Output of running " + command + " is: ");
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
here is the test.sh script
echo Hello im the script, here your args $#
Here the output
Output of running [Ljava.lang.String;#604e9f7f is:
Hello im the script, here your args Argument1
What I think is just that your startRegression.sh exit with a non-0 status (aka it failed somewhere) and it have repercussion, runTemporaryTestSuite.sh will also exit with a non-zero status, and so on hence the message : Exit Value of p2 is 1
What I see right now,
SUITE_PATH="./"
java -DconfigPath=${SUITE_PATH}/config.xml [..] the configPath will be .//config.xml so maybe you have a plain file not found issue? I might be wrong, hope it helped

Related

Runtime.getRuntime.exec() Error codes

I am trying to use runtime.getruntime.exec in a Java application.
For quite a while, I've been trying to run different command and I keep getting Error Code 2 which I've found to mean that the file or directory doesn't exist. To test, I attempted to pass a basic command and am getting Error Code 1. Why am I getting this and what does Error Code 1 mean?
Here is my code:
private String executeCommand(String command) {
logger.info("executing command : " + command);
String result = null;
try {
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(command);
BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
String line = null;
while ((line = input.readLine()) != null) {
result = result + line;
}
while ((line = stdError.readLine()) != null) {
result = result + line;
}
int exitVal = pr.waitFor();
System.out.println("Exited with error code " + exitVal);
} catch (IOException e) {
e.printStackTrace();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (Throwable e) {
e.printStackTrace();
}
logger.info("This is the result:" + result);
return result;
Here is how I call it:
String temp = executeCommand("cd $HOME/my-directory/my-subdirectory");
Here is my output:
INFO : programname - executing command : cd $HOME/my-directory/my-
subdirectory
Exited with error code 1
INFO : programname - This is the result:null/usr/bin/cd[8]: $HOME/my-
directory/my-subdirectory: not found
Runtime.getRuntime().exec(command) is expecting an exe file as its first parameter in the passed string. Commands like (cd, echo, etc...) are specific for the Command Line Tool and will not work as directly passed commands. You will need to invoke the command line tool first and then pass your command as it's arguments:
// Invoke Command Line Tool (.exe is optional) (cmd for windows sh for Linux)
// 1st argument indicates you want to run a command (/C for windows -c for Linux)
// 2nd argument is the cmd line command to run (echo)
Runtime.getRuntime().exec("cmd.exe /C echo helloworld");
Runtime.getRuntime().exec("sh -c echo helloworld");
On a separate note. you will want to initialize your result to be an empty string instead of null. Otherwise the word "null" will be prepended to what your printing out.
Do Process pr = rt.exec("cmd /c "+command);

getting error from java

How can I call a shell script through java code?
I have writtent the below code.
I am getting the process exit code as 127.
But it seems my shell script in unix machine is never called.
String scriptName = "/xyz/downloads/Report/Mail.sh";
String[] commands = {scriptName,emailid,subject,body};
Runtime rt = Runtime.getRuntime();
Process process = null;
try{
process = rt.exec(commands);
process.waitFor();
int x = process.exitValue();
System.out.println("exitCode "+x);
}catch(Exception e){
e.printStackTrace();
}
From this post here 127 Return code from $?
You get the error code if a command is not found within the PATH or the script has no +x mode.
You can have the code below to print out the exact output
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s= null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
BufferedReader stdOut = new BufferedReader(new InputStreamReader(process. getErrorStream()));
String s= null;
while ((s = stdOut.readLine()) != null) {
System.out.println(s);
}
If you are getting an exit code, then your script is executed. There is a command that you are running inside of "Mail.sh", which is not succeccfully executed and returning a status code of 127.
There could be some paths that are explicitly set in your shell, but is not available to the script, when executed outside of the shell.
Try this...
Check if you are able to run /xyz/downloads/Report/Mail.sh in a shell terminal. Fix the errors if you have any.
If there are no errors when you run this in a terminal, then try running the command using a shell in your java program.
String[] commands = {"/bin/sh", "-c", scriptName,emailid,subject,body};
(Check #John Muiruri's answer to get the complete output of your command. You can see where exactly your script is failing, if you add those lines of code)

Executing grep command on Linux from Java always returning null

I am executing grep command from java on a linux file. Its always returning null for the following code.
Process p;
String matchStr="testmatch";
String output = null;
try {
String command = "grep \""+matchStr+"\" "+ filename;
System.out.println("Running command: " + command);
p = Runtime.getRuntime().exec(command);
System.out.println("***********************************");
System.out.println("***********************************");
System.out.println("***********************************");
p.waitFor();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
while (br.readLine() != null) {
System.out.println("in while loop");
System.out.println("in while loop");
System.out.println("in while loop");
System.out.println(output);
System.out.println("***********************************");
System.out.println("***********************************");
System.out.println("***********************************");
System.out.println("***********************************");
// Process your output here
}
System.out.println("exit: " + p.exitValue());
p.destroy();
} catch (Exception e) {
e.printStackTrace();
}
If i grep it directly it shows output but from java it never gets into while loop.
Please suggest whats wrong here.
The problem is that you do not write anything to output so it stays null. I guess you have to rewrite your while loop like this
while ((output = br.readLine()) != null) {
// Process your output here
}
Take a note that this syntax is discouraged by most style check due to it's abmiguity
Also it's a good idea to place p.waitFor() after while loop so grep would not hang on flushig std(err|out).
UPDATE
Also it is a good idea to use ProcessBuilder (available since java-7) instead of Runtime.getRuntime().exec(...) because you will have more control over the process i.e
final ProcessBuilder builder = new ProcessBuilder();
builder.command("grep", matchStr, filename);
// redirect stderr to stdout
builder.redirectErrorStream(true);
final Process process = builder.start();
BufferedReader br = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String output = null;
while ((output = br.readLine()) != null) {
System.out.println(output);
// Process your output here
}
process.waitFor();
After turning your code into a https://stackoverflow.com/help/mcve it works for me.
Here the file does not exist:
robert#habanero:~$ rm /home/robert/greptest.txt
robert#habanero:~$ javac GrepTest.java && java GrepTest
Running command: grep test /home/robert/greptest.txt
exit: 2
Now the file does exist but does not contain the text to be found:
robert#habanero:~$ echo not found > /home/robert/greptest.txt
robert#habanero:~$ javac GrepTest.java && java GrepTest
Running command: grep test /home/robert/greptest.txt
exit: 1
Now the file exists and contains the text:
robert#habanero:~$ echo test this > /home/robert/greptest.txt
robert#habanero:~$ javac GrepTest.java && java GrepTest
Running command: grep test /home/robert/greptest.txt
test this
exit: 0
Here is the code:
import java.io.*;
public class GrepTest {
public static void main(String[] args) throws Exception {
String command = "grep test /home/robert/greptest.txt";
System.out.println("Running command: " + command);
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String output;
while ((output = br.readLine()) != null) {
System.out.println(output);
}
System.out.println("exit: " + p.exitValue());
p.destroy();
}
}
I was recently struggling with a similar issue, and I believe I the solution I found is an answer also to your problem (though your question is a bit malformed as others have pointed out).
The issue pertrains to the quote marks around your search string,
\""+matchStr+"\"
The java exec command will literally deliver these to the grep command, and instead of searching for matchStr, grep will be looking for "matchStr", and the results will not be what you are expecting.
This applies also in case one is executing the command as an array like
final Process process = Runtime.getRuntime().exec(new String[] { "grep", "-C1000", searchString, fileName } );
Pass the plain searchString without including quotation marks into the string.

Execute external Java code and get output

I want to execute a Java CLI-program from within another Java program and get the output of the CLI-program. I've tried two different implementations (using runtime.exec() and ProcessBuilder) and they don't quite work.
Here's the peculiar part; the implementations work (catch the output) for when executing commands such as pwd but for some reason they do not catch the output of a Hello World java program executed with java Hello.
Execution code:
public static void executeCommand(String command)
{
System.out.println("Command: \"" + command + "\"");
Runtime runtime = Runtime.getRuntime();
try
{
Process process = runtime.exec(command);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(process.getErrorStream()));
// read the output from the command
System.out.println("Standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
} catch (Exception e)
{
e.printStackTrace();
}
}
Example output
Command: "cd /Users/axelkennedal/Desktop && java Hello"
Standard output of the command:
Standard error of the command (if any):
Command: "pwd"
Standard output of the command:
/Users/axelkennedal/Dropbox/Programmering/Java/JavaFX/Kode
Standard error of the command (if any):
I have verified that Hello does indeed print "Hello world" to the CLI when running Hello directly from the CLI instead of via executeCommand().
Hello world
public class Hello
{
public static void main(String[] args)
{
System.out.println("Hello world!");
}
}
This "cd /Users/axelkennedal/Desktop && java Hello" is not one command but two commands separated by the &&. In general it means do the first command and if the first command succeeds do the second command. You can't pass this as a single command but you can implement the logic yourself:
eg to execute "cmd1 && cmd2"
if (Runtime.getRuntime().exec("cmd1").waitFor() == 0) {
Runtime.getRuntime().exec("cmd2").waitFor();
}
However, because in this case cmd1 is to change directories there is a better way, which is to use the directory function of ProcessBuilder instead of the first command.
Process p = new ProcessBuilder("java","hello")
.directory(new File("/Users/axelkennedal/Desktop"))
.start();

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.

Categories