从Java运行Unix命令非常简单。
Runtime.getRuntime().exec(myCommand);
但是能否从Java代码中运行Unix shell脚本呢?如果可以,从Java代码中运行shell脚本是否是一种好的实践方式呢?
从Java运行Unix命令非常简单。
Runtime.getRuntime().exec(myCommand);
但是能否从Java代码中运行Unix shell脚本呢?如果可以,从Java代码中运行shell脚本是否是一种好的实践方式呢?
你真的应该看一下Process Builder。它确实是为这种情况而构建的。
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();
示例:
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");
}
}
更多参考资料可以在Apache Doc中找到示例。
DefaultExecuter.setStreamHandler
方法为DefaultExecuter
设置OutputStream
以捕获OutputStream
中的输出。请参考此线程获取更多信息:如何捕获命令的输出... - Not a bug我认为您已经用以下方式回答了自己的问题:
Runtime.getRuntime().exec(myShellScript);
关于是否需要使用Shell脚本...你用Shell脚本做什么事情,用Java无法实现呢?
我认为,在Java的精神中,从Java运行shell脚本并不是一个好主意。Java旨在跨平台,而运行shell脚本会将其使用限制在UNIX系统上。
话虽如此,从Java中运行shell脚本是完全可能的。您可以使用与您列出的语法完全相同的方式(我自己尚未尝试过,但可以尝试直接执行shell脚本,如果不起作用,则执行shell本身,并将脚本作为命令行参数传递给它)。
switches
和if
语句来处理所有微妙之处,在不同平台上这些微妙之处可能并不完全相同,尽管Java核心库的开发人员已经尽力解决这个问题。 - Brian Sweeney是的,这是可能的。这对我很有效。
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());
}
}
这是我的例子,希望它有意义。
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[] {"/bin/sh", "-c", filePath}, 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;
}
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!");
}
}
是的,这是可能的,而且你已经回答了它!关于良好的实践,我认为最好从文件中启动命令,而不是直接从您的代码中启动。因此,您需要让Java在现有的.bat
、.sh
、.ksh
……文件中执行一系列命令(或一个命令)。
以下是在文件MyFile.sh
中执行一系列命令的示例:
String[] cmd = { "sh", "MyFile.sh", "\pathOfTheFile"};
Runtime.getRuntime().exec(cmd);
以下是如何在Java中运行Unix Bash或Windows批处理/cmd脚本的示例。可以在脚本上传递参数并接收来自脚本的输出。该方法可接受任意数量的参数。
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);
}
}
在Unix/Linux上运行时,路径必须类似于Unix(使用“/”作为分隔符),在Windows上运行时 - 使用“\”。以下是一个bash脚本(test.sh)的示例,它接收任意数量的参数并将每个参数加倍:
#!/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")
在Unix/Linux上,输出结果如下:
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
@echo off
set a=0
for %%x in (%*) do Set /A a+=1
echo %a% arguments received
runScript("path_to_script\\test.cmd", "1", "2", "3")
Received from script: 3 arguments received
这是一个晚回答。然而,我认为将我为了让一个shell脚本从Spring-Boot应用程序中执行所必须承受的困难记录下来,以供未来开发人员参考。
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.
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
<include>**/*.sh</include>
</includes>
</resource>
</resources>
error code = 13, Permission Denied
. Then I had to make the file executable by running this command - chmod u+x myShellScript.sh
最终,我可以使用以下代码片段来执行该文件。
public void runScript() {
ProcessBuilder pb = new ProcessBuilder("src/main/resources/myFile.sh");
try {
Process p;
p = pb.start();
} catch (IOException e) {
e.printStackTrace();
}
}
希望这能解决某些人的问题。