How to run Unix shell script from Java code?
But is it possible to run a Unix shell script from Java code? If yes, would it be a good practice to run a shell script from within Java code?
what is myCommand variable is that String? if yes, then it will not work, exec method requires String[] and argument, see below my answar, it works perfectly
17 Answers 17
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 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();
Note that that you may need to specify the program /bin/bash or sh to execute the script within depending on Java’s configuration (see stackoverflow.com/questions/25647806/…)
@Milhous I know this is quite late and things might have changed but per current Java Process documentation this is not recommended method for shell scripts: docs.oracle.com/javase/8/docs/api/java/lang/Process.html «The methods that create processes may not work well for special processes on certain native platforms, such as native windowing processes, daemon processes, Win16/DOS processes on Microsoft Windows, or shell scripts.»
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.
@KisHanSarsecHaGajjar can we also capture the output from shellscript and display it in the java ui. I want to know is it possible to do so
@KranthiSama You can set OutputStream for DefaultExecuter using DefaultExecuter.setStreamHandler method to capture output in OutputStream . Please refer this thread for more info : How can I capture the output of a command.
Link to add Apache Commons Exec library dependency to your project — commons.apache.org/proper/commons-exec/dependency-info.html
I think you have answered your own question with
Runtime.getRuntime().exec(myShellScript);
As to whether it is good practice. what are you trying to do with a shell script that you cannot do with Java?
I’ve faced a similar situation where I need to rsync a few files on different servers when a certain condition occurs in my java code. Is there any other better way ?
@Chris Ballance. I Know this comment is almost after 10 years:) but to answer your question , what if my program has to interact with half a dozen downstream and upstream channels and dependent on their accepted mode of communication. Especially when you are working on a project which interacts with so many odd channels 🙂
Pushing the functionality out to a shell script would be a last-ditch effort if there’s no other way to do the work in Java. It will be necessarily complicated to coordinate state and dependencies if you’re pushing the work out to a shell script. Occasionally, a shell script is the only way or timeframe makes it the only reasonable way to accomplish a bit of work, so this is a way to do that.
Another use case is debugging in production. What if there is some intermittent issue that cannot be reproduced, and you need to capture network stats whenever the issue occurs, for example. It has to be done programmatically from the main java app.
I would say that it is not in the spirit of Java to run a shell script from Java. Java is meant to be cross platform, and running a shell script would limit its use to just UNIX.
With that said, it’s definitely possible to run a shell script from within Java. You’d use exactly the same syntax you listed (I haven’t tried it myself, but try executing the shell script directly, and if that doesn’t work, execute the shell itself, passing the script in as a command line parameter).
what’s mythical about it is, that you usually end up writing numerous switches and if statements to get around all of the nuances that don’t work exactly the same on different platforms despite the best efforts of the people who came up with the java core libraries.
@BobbyShaftoe I have been writing java for 16 years, and always developed on windows, all my apps always deployed on solaris/ibm or oracle flavored unix boxes, so I have no idea what you are talking about
@KalpeshSoni that is the reason; you always have a fixed target deploy platform; case is different when you have to deploy to Windows, Linux, Mac and Solaris simultaneously.
Yes it is possible to do so. This worked out for me.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import org.omg.CORBA.portable.InputStream; public static void readBashScript() < try < Process proc = Runtime.getRuntime().exec("/home/destino/workspace/JavaProject/listing.sh /"); //Whatever you want to execute BufferedReader read = new BufferedReader(new InputStreamReader( proc.getInputStream())); try < proc.waitFor(); >catch (InterruptedException e) < System.out.println(e.getMessage()); >while (read.ready()) < System.out.println(read.readLine()); >> catch (IOException e) < System.out.println(e.getMessage()); >>
Here is my example. Hope it make sense.
public static void excuteCommand(String filePath) throws IOException < File file = new File(filePath); if(!file.isFile())< throw new IllegalArgumentException("The file " + filePath + " does not exist"); >if(isLinux())< Runtime.getRuntime().exec(new String[] , null); >else if(isWindows()) < Runtime.getRuntime().exec("cmd /c start " + filePath); >> public static boolean isLinux()< String os = System.getProperty("os.name"); return os.toLowerCase().indexOf("linux") >= 0; > public static boolean isWindows()< String os = System.getProperty("os.name"); return os.toLowerCase().indexOf("windows") >= 0; >
To avoid having to hardcode an absolute path, you can use the following method that will find and execute your script if it is in your root directory.
public static void runScript() throws IOException, InterruptedException < ProcessBuilder processBuilder = new ProcessBuilder("./nameOfScript.sh"); //Sets the source and destination for subprocess standard I/O to be the same as those of the current Java process. processBuilder.inheritIO(); Process process = processBuilder.start(); int exitValue = process.waitFor(); if (exitValue != 0) < // check for errors new BufferedInputStream(process.getErrorStream()); throw new RuntimeException("execution of script failed!"); >>
Yes, it is possible and you have answered it! About good practises, I think it is better to launch commands from files and not directly from your code. So you have to make Java execute the list of commands (or one command) in an existing .bat , .sh , .ksh . files. Here is an example of executing a list of commands in a file MyFile.sh :
String[] cmd = < "sh", "MyFile.sh", "\pathOfTheFile">; Runtime.getRuntime().exec(cmd);
As for me all things must be simple. For running script just need to execute
new ProcessBuilder("pathToYourShellScript").start();
The ZT Process Executor library is an alternative to Apache Commons Exec. It has functionality to run commands, capturing their output, setting timeouts, etc.
I have not used it yet, but it looks reasonably well-documented.
An example from the documentation: Executing a command, pumping the stderr to a logger, returning the output as UTF8 string.
String output = new ProcessExecutor().command("java", "-version") .redirectError(Slf4jStream.of(getClass()).asInfo()) .readOutput(true).execute() .outputUTF8();
Its documentation lists the following advantages over Commons Exec:
- Improved handling of streams
- Reading/writing to streams
- Redirecting stderr to stdout
- One liners for quite complex use cases
- One liners to get process output into a String
- Access to the Process object available
- Support for async processes ( Future )
This is a late answer. However, I thought of putting the struggle I had to bear to get a shell script to be executed from a Spring-Boot application for future developers.
- I was working in Spring-Boot and I was not able to find the file to be executed from my Java application and it was throwing FileNotFoundFoundException . I had to keep the file in the resources directory and had to set the file to be scanned in pom.xml while the application was being started like the following.
src/main/resources true **/*.xml **/*.properties **/*.sh Finally, I could execute the file using the following code snippet.
public void runScript() < ProcessBuilder pb = new ProcessBuilder("src/main/resources/myFile.sh"); try < Process p; p = pb.start(); >catch (IOException e) < e.printStackTrace(); >>
Hope that solves someone’s problem.
Here is an example how to run an Unix bash or Windows bat/cmd script from Java. Arguments can be passed on the script and output received from the script. The method accepts arbitrary number of arguments.
public static void runScript(String path, String. args) < try < String[] cmd = new String[args.length + 1]; cmd[0] = path; int count = 0; for (String s : args) < cmd[++count] = args[count - 1]; >Process process = Runtime.getRuntime().exec(cmd); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); try < process.waitFor(); >catch (Exception ex) < System.out.println(ex.getMessage()); >while (bufferedReader.ready()) < System.out.println("Received from script: " + bufferedReader.readLine()); >> catch (Exception ex) < System.out.println(ex.getMessage()); System.exit(1); >>
When running on Unix/Linux, the path must be Unix-like (with ‘/’ as separator), when running on Windows — use ‘\’. Hier is an example of a bash script (test.sh) that receives arbitrary number of arguments and doubles every argument:
#!/bin/bash counter=0 while [ $# -gt 0 ] do echo argument $((counter +=1)): $1 echo doubling argument $((counter)): $(($1+$1)) shift done
runScript("path_to_script/test.sh", "1", "2")
on Unix/Linux, the output is:
Received from script: argument 1: 1 Received from script: doubling argument 1: 2 Received from script: argument 2: 2 Received from script: doubling argument 2: 4
Hier is a simple cmd Windows script test.cmd that counts number of input arguments:
@echo off set a=0 for %%x in (%*) do Set /A a+=1 echo %a% arguments received
When calling the script on Windows
runScript("path_to_script\\test.cmd", "1", "2", "3")
Received from script: 3 arguments received
It is possible, just exec it as any other program. Just make sure your script has the proper #! (she-bang) line as the first line of the script, and make sure there are execute permissions on the file.
For example, if it is a bash script put #!/bin/bash at the top of the script, also chmod +x .
Also as for if it’s good practice, no it’s not, especially for Java, but if it saves you a lot of time porting a large script over, and you’re not getting paid extra to do it 😉 save your time, exec the script, and put the porting to Java on your long-term todo list.
Checking the operating system on can manage the shell/bash scrips if such are supported. if there is need to make the code portable.
String scriptName = PATH+"/myScript.sh"; String commands[] = new String[]; Runtime rt = Runtime.getRuntime(); Process process = null; try< process = rt.exec(commands); process.waitFor(); >catch(Exception e)
Just the same thing that Solaris 5.10 it works like this ./batchstart.sh there is a trick I don´t know if your OS accept it use \\. batchstart.sh instead. This double slash may help.
public static void runShell(String directory, String command, String[] args, Map environment) < try < if(directory.trim().equals("")) directory = "/"; String[] cmd = new String[args.length + 1]; cmd[0] = command; int count = 1; for(String s : args) < cmd[count] = s; count++; >ProcessBuilder pb = new ProcessBuilder(cmd); Map env = pb.environment(); for(String s : environment.keySet()) env.put(s, environment.get(s)); pb.directory(new File(directory)); Process process = pb.start(); BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream())); BufferedWriter outputReader = new BufferedWriter(new OutputStreamWriter(process.getOutputStream())); BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); int exitValue = process.waitFor(); if(exitValue != 0) // has errors < while(errReader.ready()) < LogClass.log("ErrShell: " + errReader.readLine(), LogClass.LogMode.LogAll); >> else < while(inputReader.ready()) < LogClass.log("Shell Result : " + inputReader.readLine(), LogClass.LogMode.LogAll); >> > catch(Exception e) < LogClass.log("Err: RunShell, " + e.toString(), LogClass.LogMode.LogAll); >> public static void runShell(String path, String command, String[] args) < try < String[] cmd = new String[args.length + 1]; if(!path.trim().isEmpty()) cmd[0] = path + "/" + command; else cmd[0] = command; int count = 1; for(String s : args) < cmd[count] = s; count++; >Process process = Runtime.getRuntime().exec(cmd); BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream())); BufferedWriter outputReader = new BufferedWriter(new OutputStreamWriter(process.getOutputStream())); BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); int exitValue = process.waitFor(); if(exitValue != 0) // has errors < while(errReader.ready()) < LogClass.log("ErrShell: " + errReader.readLine(), LogClass.LogMode.LogAll); >> else < while(inputReader.ready()) < LogClass.log("Shell Result: " + inputReader.readLine(), LogClass.LogMode.LogAll); >> > catch(Exception e) < LogClass.log("Err: RunShell, " + e.toString(), LogClass.LogMode.LogAll); >>
ShellAssistance.runShell("", "pg_dump", new String[]);
ShellAssistance.runShell("", "pg_dump", new String[], new Hashmap<>());
Highly active question. Earn 10 reputation (not counting the association bonus) in order to answer this question. The reputation requirement helps protect this question from spam and non-answer activity.
Linked
Related
Hot Network Questions
Subscribe to RSS
To subscribe to this RSS feed, copy and paste this URL into your RSS reader.
Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.14.43533
By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.
how to run a command at terminal from java program?
Update: As suggested by xav, it is advisable to use ProcessBuilder instead:
String[] args = new String[] ; Process proc = new ProcessBuilder(args).start();
Usage of Runtime.exec() is now discouraged: use shall use ProcessBuilder instead (docs.oracle.com/javase/7/docs/api/java/lang/…)
I vote for Karthik T’s answer. you don’t need to open a terminal to run commands.
// file: RunShellCommandFromJava.java import java.io.BufferedReader; import java.io.InputStreamReader; public class RunShellCommandFromJava < public static void main(String[] args) < String command = "ping -c 3 www.google.com"; Process proc = Runtime.getRuntime().exec(command); // Read the output BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream())); String line = ""; while((line = reader.readLine()) != null) < System.out.print(line + "\n"); >proc.waitFor(); > >
$ javac RunShellCommandFromJava.java $ java RunShellCommandFromJava PING http://google.com (123.125.81.12): 56 data bytes 64 bytes from 123.125.81.12: icmp_seq=0 ttl=59 time=108.771 ms 64 bytes from 123.125.81.12: icmp_seq=1 ttl=59 time=119.601 ms 64 bytes from 123.125.81.12: icmp_seq=2 ttl=59 time=11.004 ms --- http://google.com ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 11.004/79.792/119.601/48.841 ms