Nó khá đơn giản để chạy một lệnh Unix từ Java.
Runtime.getRuntime().exec(myCommand);
Nhưng có thể chạy tập lệnh shell Unix từ mã Java không? Nếu có, nó có phải là một cách thực hành tốt để chạy một tập lệnh shell từ bên trong mã Java không?
Nó khá đơn giản để chạy một lệnh Unix từ Java.
Runtime.getRuntime().exec(myCommand);
Nhưng có thể chạy tập lệnh shell Unix từ mã Java không? Nếu có, nó có phải là một cách thực hành tốt để chạy một tập lệnh shell từ bên trong mã Java không?
Câu trả lời:
Bạn thực sự nên nhìn vào Process Builder . Nó thực sự được xây dựng cho loại điều này.
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();
Bạn cũng có thể sử dụng thư viện exec của Apache Commons .
Thí dụ :
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");
}
}
Để tham khảo thêm, Một ví dụ cũng được đưa ra trên Apache Doc .
OutputStream
để DefaultExecuter
sử dụng DefaultExecuter.setStreamHandler
phương thức để nắm bắt đầu ra OutputStream
. Vui lòng tham khảo chủ đề này để biết thêm thông tin: Làm cách nào tôi có thể nắm bắt được đầu ra của lệnh ...
Tôi muốn nói rằng nó không phải là tinh thần của Java để chạy một kịch bản shell từ Java. Java có nghĩa là đa nền tảng và việc chạy một kịch bản shell sẽ giới hạn việc sử dụng nó chỉ là UNIX.
Như đã nói, chắc chắn có thể chạy một tập lệnh shell từ bên trong Java. Bạn sẽ sử dụng chính xác cùng một cú pháp mà bạn đã liệt kê (Tôi đã tự mình thử nó, nhưng hãy thử thực thi trực tiếp tập lệnh shell và nếu nó không hoạt động, hãy tự thực thi trình bao, chuyển tập lệnh thành tham số dòng lệnh) .
switches
và if
phát biểu để giải quyết tất cả các sắc thái không hoạt động giống hệt nhau trên các nền tảng khác nhau bất chấp những nỗ lực tốt nhất của những người đã đưa ra các thư viện lõi java.
Tôi nghĩ rằng bạn đã trả lời câu hỏi của riêng bạn với
Runtime.getRuntime().exec(myShellScript);
Về việc liệu đó có phải là một thực tiễn tốt hay không ... bạn đang cố gắng làm gì với một tập lệnh shell mà bạn không thể làm với Java?
Có nó có thể làm như vậy. Điều này làm việc cho tôi.
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());
}
}
Đây là ví dụ của tôi. Hy vọng nó có ý nghĩa.
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;
}
Vâng, nó là có thể và bạn đã trả lời nó! Về thực hành tốt, tôi nghĩ tốt hơn là khởi chạy các lệnh từ tệp chứ không phải trực tiếp từ mã của bạn. Vì vậy, bạn cần phải thực hiện Java thực hiện danh sách các lệnh (hoặc một lệnh) trong hiện một .bat
, .sh
, .ksh
file .... Dưới đây là một ví dụ về thực thi danh sách các lệnh trong một tệp MyFile.sh
:
String[] cmd = { "sh", "MyFile.sh", "\pathOfTheFile"};
Runtime.getRuntime().exec(cmd);
Để tránh phải mã hóa một đường dẫn tuyệt đối, bạn có thể sử dụng phương pháp sau đây sẽ tìm và thực thi tập lệnh của mình nếu nó nằm trong thư mục gốc của bạn.
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!");
}
}
Đối với tôi tất cả mọi thứ phải đơn giản. Để chạy script chỉ cần thực thi
new ProcessBuilder("pathToYourShellScript").start();
Các ZT Process Executor thư viện là một thay thế cho Apache Commons Exec. Nó có chức năng chạy các lệnh, nắm bắt đầu ra của chúng, thiết lập thời gian chờ, v.v.
Tôi chưa sử dụng nó, nhưng nó có vẻ được tài liệu hợp lý.
Một ví dụ từ tài liệu: Thực hiện một lệnh, bơm stderr vào một logger, trả về đầu ra dưới dạng chuỗi UTF8.
String output = new ProcessExecutor().command("java", "-version")
.redirectError(Slf4jStream.of(getClass()).asInfo())
.readOutput(true).execute()
.outputUTF8();
Tài liệu của nó liệt kê các ưu điểm sau so với Commons Exec:
Dưới đây là một ví dụ về cách chạy tập lệnh bash Unix hoặc Windows bat / cmd từ Java. Các đối số có thể được truyền vào tập lệnh và đầu ra nhận được từ tập lệnh. Phương thức chấp nhận số lượng đối số tùy ý.
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);
}
}
Khi chạy trên Unix / Linux, đường dẫn phải giống như Unix (với '/' là dấu phân cách), khi chạy trên Windows - sử dụng '\'. Hier là một ví dụ về tập lệnh bash (test.sh) nhận số lượng đối số tùy ý và nhân đôi mọi đối số:
#!/bin/bash
counter=0
while [ $# -gt 0 ]
do
echo argument $((counter +=1)): $1
echo doubling argument $((counter)): $(($1+$1))
shift
done
Khi gọi
runScript("path_to_script/test.sh", "1", "2")
trên Unix / Linux, đầu ra là:
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 là một tập lệnh Windows cmd đơn giản test.cmd đếm số lượng đối số đầu vào:
@echo off
set a=0
for %%x in (%*) do Set /A a+=1
echo %a% arguments received
Khi gọi tập lệnh trên Windows
runScript("path_to_script\\test.cmd", "1", "2", "3")
Đầu ra là
Received from script: 3 arguments received
Có thể, chỉ cần thực hiện nó như bất kỳ chương trình khác. Chỉ cần chắc chắn rằng tập lệnh của bạn có # đúng! (she-bang) là dòng đầu tiên của tập lệnh và đảm bảo có các quyền thực thi trên tệp.
Ví dụ: nếu đó là tập lệnh bash, hãy đặt #! / Bin / bash ở đầu tập lệnh, cũng là chmod + x.
Ngoài ra, nếu nó là một cách thực hành tốt, thì không, đặc biệt là đối với Java, nhưng nếu nó giúp bạn tiết kiệm rất nhiều thời gian để chuyển một tập lệnh lớn và bạn sẽ không được trả thêm tiền để làm điều đó;) hãy tiết kiệm thời gian của bạn, thực hiện tập lệnh và đưa tính năng chuyển sang Java vào danh sách việc cần làm dài hạn của bạn.
String scriptName = PATH+"/myScript.sh";
String commands[] = new String[]{scriptName,"myArg1", "myArg2"};
Runtime rt = Runtime.getRuntime();
Process process = null;
try{
process = rt.exec(commands);
process.waitFor();
}catch(Exception e){
e.printStackTrace();
}
Đây là một câu trả lời muộn. Tuy nhiên, tôi đã nghĩ đến việc đặt cuộc đấu tranh mà tôi phải chịu để có được một kịch bản shell được thực thi từ ứng dụng Spring-Boot cho các nhà phát triển trong tương lai.
Tôi đã làm việc trong Spring-Boot và tôi không thể tìm thấy tệp được thực thi từ ứng dụng Java của mình và nó đã bị ném FileNotFoundFoundException
. Tôi phải giữ tập tin trong resources
thư mục và phải đặt tập tin được quét trong pom.xml
khi ứng dụng đang được khởi động như sau.
<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
. Sau đó, tôi phải làm cho tập tin thực thi bằng cách chạy lệnh này -chmod u+x myShellScript.sh
Cuối cùng, tôi có thể thực thi tệp bằng đoạn mã sau.
public void runScript() {
ProcessBuilder pb = new ProcessBuilder("src/main/resources/myFile.sh");
try {
Process p;
p = pb.start();
} catch (IOException e) {
e.printStackTrace();
}
}
Hy vọng rằng giải quyết vấn đề của ai đó.
để sử dụng linux
public static void runShell(String directory, String command, String[] args, Map<String, String> 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<String, String> 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);
}
}
và để sử dụng;
ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"});
HOẶC LÀ
ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"}, new Hashmap<>());