You should really look at Process Builder. It is really built for this kind of thing.
ProcessBuilder pb = new ProcessBuilder("myshellScript.sh", "myArg1", "myArg2");
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
Process p = pb.start();
Answer from Milhous on Stack OverflowYou should really look at Process Builder. It is really built for this kind of thing.
ProcessBuilder pb = new ProcessBuilder("myshellScript.sh", "myArg1", "myArg2");
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
Process p = pb.start();
You can use Apache Commons exec library also.
Example :
package testShellScript;
import java.io.IOException;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
public class TestScript {
int iExitValue;
String sCommandString;
public void runScript(String command){
sCommandString = command;
CommandLine oCmdLine = CommandLine.parse(sCommandString);
DefaultExecutor oDefaultExecutor = new DefaultExecutor();
oDefaultExecutor.setExitValue(0);
try {
iExitValue = oDefaultExecutor.execute(oCmdLine);
} catch (ExecuteException e) {
System.err.println("Execution failed.");
e.printStackTrace();
} catch (IOException e) {
System.err.println("permission denied.");
e.printStackTrace();
}
}
public static void main(String args[]){
TestScript testScript = new TestScript();
testScript.runScript("sh /root/Desktop/testScript.sh");
}
}
For further reference, An example is given on Apache Doc also.
Videos
You should use the returned Process to get the result.
Runtime#exec executes the command as a separate process and returns an object of type Process. You should call Process#waitFor so that your program waits until the new process finishes. Then, you can invoke Process.html#getOutputStream() on the returned Process object to inspect the output of the executed command.
An alternative way of creating a process is to use ProcessBuilder.
Process p = new ProcessBuilder("myCommand", "myArg").start();
With a ProcessBuilder, you list the arguments of the command as separate arguments.
See Difference between ProcessBuilder and Runtime.exec() and ProcessBuilder vs Runtime.exec() to learn more about the differences between Runtime#exec and ProcessBuilder#start.
When you execute a script from Java it spawns a new shell where the PATH environment variable is not set.
Setting the PATH env variable using the below code should run your script.
String[] env = {"PATH=/bin:/usr/bin/"};
String cmd = "you complete shell command"; //e.g test.sh -dparam1 -oout.txt
Process process = Runtime.getRuntime().exec(cmd, env);
You should be able to use Runtime.exec() or ProcessBuilder to invoke a shell to run a script, but the whole process is full of pitfalls.
I would suggest reading this article:
https://www.infoworld.com/article/2071275/when-runtime-exec---won-t.html
which explains many of these pitfalls, and how to avoid them. In particular, on Linux you'll almost certainly need to consume stdout and stderr from your shell invocation -- that's sometimes true even if the script doesn't produce any output. You'll also need to be careful how you handle spaces and special characters -- if there are any -- in the arguments to your script. The parser that Java uses for the command line blindly breaks a command line at whitespace.
Take a look at this Runtime.getRunTime().exec
Make sure bash.exe is in PATH as Charles Duffy said. Having bash installed without that being the case, is, after all, not much use. When that's the case and your script is in the current directory, the following is equivalent to your code:
public class Test {
public static void main(String[] args) throws Exception {
String[] command = { "bash", "test.sh" };
ProcessBuilder pb = new ProcessBuilder(command).inheritIO();
Process p = pb.start();
p.waitFor();
System.out.println(p.exitValue());
}
}
Note: You should use ProcessBuilder to launch as it provides better control over I/O streams, and the Runtime.exec call you use is deprecated. However the outcome would be the same in your case.
The issue here is that bash on Windows is expecting a Linux style pathname, and you are passing in Windows OS pathname.
Your Path environment for bash.exe is correct because you don't get IOException : Cannot run program "bash.exe": CreateProcess error=2, The system cannot find the file specified.
Thus bash.exe has run, but it reports exit code 127 which means Command not found, or PATH error. To fix you need to form valid GNU/Linux pathname to the script. If you are using WSL the C drive is mapped as "/mnt/c" so you need to run the translated path:
String[] cmd = new String[]{ "bash.exe", "/mnt/c/Users/abc/Downloads/test.sh" };
// Using "bash" above should also work if "bash.exe" is in the Path and PATHEXT contains ".EXE"
Process p = new ProcessBuilder(cmd).redirectErrorStream(true).start();
p.getInputStream().transferTo(System.out);
System.out.println(p.waitFor());
You could avoid the OS pathname translation by using a relative path to the script and run from it's directory:
File exe = new File("C:\\Users\\abc\\Downloads\\test.sh");
// Set up relative path for the script
String[] cmd = new String[]{"bash", exe.getName()};
ProcessBuilder pb = new ProcessBuilder(cmd).redirectErrorStream(true);
// Run from the directory of the script:
pb.directory(exe.getParentFile());
Process p = pb.start();
p.getInputStream().transferTo(System.out);
System.out.println(p.waitFor());