มันค่อนข้างง่ายในการเรียกใช้คำสั่ง Unix จาก Java
Runtime.getRuntime().exec(myCommand);
แต่มันเป็นไปได้ไหมที่จะรันเชลล์สคริปต์ Unix จากโค้ด Java? ถ้าใช่จะเป็นการดีที่จะใช้เชลล์สคริปต์จากภายในโค้ด Java หรือไม่?
มันค่อนข้างง่ายในการเรียกใช้คำสั่ง Unix จาก Java
Runtime.getRuntime().exec(myCommand);
แต่มันเป็นไปได้ไหมที่จะรันเชลล์สคริปต์ Unix จากโค้ด Java? ถ้าใช่จะเป็นการดีที่จะใช้เชลล์สคริปต์จากภายในโค้ด Java หรือไม่?
คำตอบ:
จริงๆคุณควรดูที่สร้างกระบวนการ มันถูกสร้างขึ้นสำหรับสิ่งนี้
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();
คุณสามารถใช้ไลบรารี Apache Commons exec ได้เช่นกัน
ตัวอย่าง:
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ด้วย
OutputStream
สำหรับDefaultExecuter
การใช้วิธีการในการส่งออกจับในDefaultExecuter.setStreamHandler
OutputStream
โปรดอ้างอิงหัวข้อนี้สำหรับข้อมูลเพิ่มเติม: ฉันจะจับเอาท์พุทของคำสั่งได้อย่างไร
ฉันจะบอกว่ามันไม่ได้อยู่ในจิตวิญญาณของ Java ที่จะเรียกใช้เชลล์สคริปต์จาก Java Java หมายถึงการเป็น cross platform และการรันเชลล์สคริปต์จะ จำกัด การใช้เพียง UNIX
จากที่กล่าวมาเป็นไปได้แน่นอนที่จะเรียกใช้เชลล์สคริปต์จากภายใน Java คุณจะใช้ไวยากรณ์เดียวกับที่คุณระบุไว้อย่างแน่นอน (ฉันไม่ได้ลองด้วยตัวเอง แต่ลองเรียกใช้งานเชลล์สคริปต์โดยตรงและหากไม่ได้ผลให้สั่งงานเชลล์เองผ่านสคริปต์ในพารามิเตอร์บรรทัดคำสั่ง) .
switches
และif
แถลงการณ์เพื่อแก้ไขความแตกต่างที่ไม่เหมือนกันบนแพลตฟอร์มที่แตกต่างกันแม้จะมีความพยายามอย่างดีที่สุดของคนที่มากับห้องสมุดแกน java
ฉันคิดว่าคุณได้ตอบคำถามของคุณด้วย
Runtime.getRuntime().exec(myShellScript);
เกี่ยวกับว่าเป็นวิธีปฏิบัติที่ดี ... คุณพยายามทำอะไรกับเชลล์สคริปต์ที่คุณไม่สามารถทำกับ Java ได้?
ใช่มันเป็นไปได้ที่จะทำเช่นนั้น สิ่งนี้ได้ผลสำหรับฉัน
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;
}
ใช่เป็นไปได้และคุณตอบแล้ว! เกี่ยวกับแนวปฏิบัติที่ดีฉันคิดว่าเป็นการดีกว่าที่จะเรียกใช้คำสั่งจากไฟล์ไม่ใช่จากรหัสของคุณโดยตรง ดังนั้นคุณจะต้องทำ Java ดำเนินรายการของคำสั่ง (หรือคำสั่งอย่างใดอย่างหนึ่ง) ในที่มีอยู่.bat
, .sh
, .ksh
... ไฟล์ นี่คือตัวอย่างของการดำเนินการรายการคำสั่งในไฟล์MyFile.sh
:
String[] cmd = { "sh", "MyFile.sh", "\pathOfTheFile"};
Runtime.getRuntime().exec(cmd);
เพื่อหลีกเลี่ยงไม่ให้ hardcode พา ธ สัมบูรณ์คุณสามารถใช้วิธีการต่อไปนี้ที่จะค้นหาและรันสคริปต์ของคุณหากอยู่ในไดเรกทอรีรากของคุณ
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!");
}
}
สำหรับฉันทุกสิ่งต้องเรียบง่าย สำหรับการรันสคริปต์ก็ต้องดำเนินการ
new ProcessBuilder("pathToYourShellScript").start();
ZT กระบวนการปฏิบัติการห้องสมุดเป็นทางเลือกให้ Apache Commons Exec มันมีฟังก์ชั่นในการเรียกใช้คำสั่งจับผลลัพธ์ของพวกเขาตั้งค่าหมดเวลา ฯลฯ
ฉันยังไม่ได้ใช้ แต่ก็มีเอกสารที่สมเหตุสมผลพอสมควร
ตัวอย่างจากเอกสารประกอบการเรียกใช้งานคำสั่งปั๊ม stderr ไปยังตัวบันทึกส่งคืนผลลัพธ์เป็นสตริง UTF8
String output = new ProcessExecutor().command("java", "-version")
.redirectError(Slf4jStream.of(getClass()).asInfo())
.readOutput(true).execute()
.outputUTF8();
เอกสารประกอบแสดงถึงข้อดีดังต่อไปนี้ของ Commons Exec:
นี่คือตัวอย่างวิธีการรัน Unix bash หรือ Windows bat / cmd script จาก Java อาร์กิวเมนต์สามารถส่งผ่านไปยังสคริปต์และเอาต์พุตที่ได้รับจากสคริปต์ วิธีการรับจำนวนข้อโต้แย้งโดยพลการ
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-like (โดยมี '/' เป็นตัวคั่น) เมื่อใช้งานบน Windows - ใช้ '\' Hier เป็นตัวอย่างของสคริปต์ทุบตี (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
Hier เป็นสคริปต์ Windows cmd แบบง่าย test.cmd ที่นับจำนวนอาร์กิวเมนต์อินพุต:
@echo off
set a=0
for %%x in (%*) do Set /A a+=1
echo %a% arguments received
เมื่อเรียกใช้สคริปต์บน Windows
runScript("path_to_script\\test.cmd", "1", "2", "3")
ผลลัพธ์คือ
Received from script: 3 arguments received
เป็นไปได้เพียงแค่ดำเนินการเป็นโปรแกรมอื่น ๆ เพียงให้แน่ใจว่าสคริปต์ของคุณมี # ที่ถูกต้อง! บรรทัด (she-bang) เป็นบรรทัดแรกของสคริปต์และตรวจสอบให้แน่ใจว่ามีการดำเนินการอนุญาตสำหรับไฟล์
ตัวอย่างเช่นหากเป็นสคริปต์ทุบตีให้ใส่ #! / bin / bash ที่ด้านบนของสคริปต์เช่นกัน chmod + x
นอกจากนี้ถ้าเป็นแนวปฏิบัติที่ดีไม่เป็นเช่นนั้นโดยเฉพาะอย่างยิ่งสำหรับ Java แต่ถ้ามันช่วยให้คุณประหยัดเวลาได้มากในการย้ายสคริปขนาดใหญ่ไปและคุณจะไม่ได้รับค่าจ้างพิเศษในการทำ;) ประหยัดเวลา สคริปต์และย้ายพอร์ตไปยัง Java ในรายการสิ่งที่ต้องทำระยะยาว
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();
}
นี่คือคำตอบที่ล่าช้า อย่างไรก็ตามฉันคิดว่าจะต้องพยายามดิ้นรนเพื่อให้ได้เชลล์สคริปต์ที่จะดำเนินการจากแอปพลิเคชัน Spring-Boot สำหรับนักพัฒนาในอนาคต
ผมทำงานในฤดูใบไม้ผลิ Boot และผมก็ไม่สามารถที่จะหาไฟล์ที่จะดำเนินการจากโปรแกรม Java FileNotFoundFoundException
ของฉันและมันถูกขว้างปา ฉันต้องเก็บไฟล์ไว้ในresources
ไดเรกทอรีและต้องตั้งค่าไฟล์ที่จะสแกนในpom.xml
ขณะที่แอปพลิเคชันเริ่มต้นดังต่อไปนี้
<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
หลังจากนั้นผมก็มีปัญหาในการดำเนินการไฟล์และมันกำลังจะกลับ จากนั้นฉันจะต้องทำให้ไฟล์ที่ปฏิบัติการได้โดยใช้คำสั่งนี้ -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();
}
}
หวังว่าจะแก้ปัญหาของใครบางคน
เช่นเดียวกับที่ Solaris 5.10 ทำงานเช่นนี้./batchstart.sh
มีเคล็ดลับที่ฉันไม่ทราบว่าระบบปฏิบัติการของคุณยอมรับว่าใช้\\. batchstart.sh
แทนหรือไม่ เครื่องหมายทับสองครั้งนี้อาจช่วยได้
ฉันคิดด้วย
System.getProperty("os.name");
การตรวจสอบระบบปฏิบัติการบนสามารถจัดการเชลล์ / bash scrips ได้หากได้รับการสนับสนุน หากจำเป็นต้องทำรหัสแบบพกพา
สำหรับการใช้งานลินุกซ์
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);
}
}
และสำหรับการใช้งาน;
ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"});
หรือ
ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"}, new Hashmap<>());