Uruchomienie polecenia Unix z poziomu Javy jest dość proste.
Runtime.getRuntime().exec(myCommand);
Ale czy można uruchomić skrypt powłoki Unix z kodu Java? Jeśli tak, czy dobrą praktyką byłoby uruchomienie skryptu powłoki z poziomu kodu Java?
Uruchomienie polecenia Unix z poziomu Javy jest dość proste.
Runtime.getRuntime().exec(myCommand);
Ale czy można uruchomić skrypt powłoki Unix z kodu Java? Jeśli tak, czy dobrą praktyką byłoby uruchomienie skryptu powłoki z poziomu kodu Java?
Odpowiedzi:
Powinieneś naprawdę spojrzeć na Process Builder . Jest naprawdę zbudowany do tego typu rzeczy.
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();
Możesz użyć biblioteki exec Apache Commons .
Przykład:
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");
}
}
W celu uzyskania dalszych informacji, podano również przykład w Apache Doc .
OutputStream
na DefaultExecuter
użyciu DefaultExecuter.setStreamHandler
metody przechwytywania w wyjściu OutputStream
. Zapoznaj się z tym wątkiem, aby uzyskać więcej informacji: Jak mogę przechwycić dane wyjściowe polecenia ...
Powiedziałbym, że nie jest to duch Javy uruchamianie skryptu powłoki z Javy. Java ma być wieloplatformowa, a uruchomienie skryptu powłoki ograniczyłoby jej użycie tylko do systemu UNIX.
Mając to na uwadze, zdecydowanie możliwe jest uruchomienie skryptu powłoki z poziomu Javy. Użyłbyś dokładnie tej samej składni, którą podałeś (sam tego nie próbowałem, ale spróbuj wykonać skrypt powłoki bezpośrednio, a jeśli to nie zadziała, uruchom samą powłokę, przekazując skrypt jako parametr wiersza poleceń) .
switches
i if
sprawozdań, aby ominąć wszystkie niuanse, które nie działają dokładnie tak samo na różnych platformach mimo najlepszych starań ludzi, którzy wpadli na bibliotekach rdzenia java.
Myślę, że odpowiedziałeś na swoje pytanie za pomocą
Runtime.getRuntime().exec(myShellScript);
Co do tego, czy jest to dobra praktyka ... co próbujesz zrobić ze skryptem powłoki, którego nie możesz zrobić w Javie?
Tak, jest to możliwe. To mi się udało.
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());
}
}
Oto mój przykład. Mam nadzieję, że to ma sens.
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;
}
Tak, jest to możliwe i odpowiedziałeś na to! Co do dobrych praktyk, myślę, że lepiej jest uruchamiać polecenia z plików, a nie bezpośrednio z kodu. Więc trzeba zrobić Java wykonać listę poleceń (lub jednego polecenia) w istniejącej .bat
, .sh
, .ksh
... plików. Oto przykład wykonania listy poleceń w pliku MyFile.sh
:
String[] cmd = { "sh", "MyFile.sh", "\pathOfTheFile"};
Runtime.getRuntime().exec(cmd);
Aby uniknąć konieczności kodowania bezwzględnej ścieżki na stałe, możesz użyć następującej metody, która znajdzie i uruchomi skrypt, jeśli znajduje się on w katalogu głównym.
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!");
}
}
Jeśli chodzi o mnie, wszystko musi być proste. Do uruchomienia skryptu wystarczy wykonać
new ProcessBuilder("pathToYourShellScript").start();
Wykonawca ZT Sposób jest alternatywą dla Apache Commons Exec. Posiada funkcję uruchamiania poleceń, przechwytywania ich danych wyjściowych, ustawiania limitów czasu itp.
Nie korzystałem jeszcze z niego, ale wygląda na dość dobrze udokumentowany.
Przykład z dokumentacji: Wykonanie polecenia, przepompowanie stderr do loggera, zwrócenie danych wyjściowych jako łańcuch znaków UTF8.
String output = new ProcessExecutor().command("java", "-version")
.redirectError(Slf4jStream.of(getClass()).asInfo())
.readOutput(true).execute()
.outputUTF8();
Jego dokumentacja wymienia następujące zalety w porównaniu z Commons Exec:
Oto przykład, jak uruchomić skrypt bash Unix lub Windows bat / cmd z poziomu Java. Argumenty mogą być przekazywane do skryptu i dane wyjściowe otrzymane ze skryptu. Metoda przyjmuje dowolną liczbę argumentów.
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);
}
}
W przypadku pracy w systemie Unix / Linux ścieżka musi być podobna do systemu Unix (z „/” jako separatorem), w przypadku uruchamiania w systemie Windows - należy użyć „\”. Hier to przykład skryptu bash (test.sh), który otrzymuje dowolną liczbę argumentów i podwaja każdy argument:
#!/bin/bash
counter=0
while [ $# -gt 0 ]
do
echo argument $((counter +=1)): $1
echo doubling argument $((counter)): $(($1+$1))
shift
done
Dzwoniąc
runScript("path_to_script/test.sh", "1", "2")
w systemie Unix / Linux dane wyjściowe to:
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 jest prostym skryptem cmd test.cmd, który zlicza argumenty wejściowe:
@echo off
set a=0
for %%x in (%*) do Set /A a+=1
echo %a% arguments received
Podczas wywoływania skryptu w systemie Windows
runScript("path_to_script\\test.cmd", "1", "2", "3")
Wynik jest
Received from script: 3 arguments received
Jest to możliwe, po prostu wykonaj to jak każdy inny program. Tylko upewnij się, że Twój skrypt ma poprawny #! (she-bang) jako pierwszą linię skryptu i upewnij się, że plik ma uprawnienia do wykonywania.
Na przykład, jeśli jest to skrypt bash, umieść #! / Bin / bash na górze skryptu, również chmod + x.
Również jeśli chodzi o dobrą praktykę, nie, zwłaszcza w przypadku Javy, ale jeśli oszczędza ci to dużo czasu przy przenoszeniu dużego skryptu i nie dostajesz za to dodatkowej zapłaty;) oszczędzaj czas, wykonaj script i umieść portowanie na Javę na długoterminowej liście rzeczy do zrobienia.
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();
}
To jest późna odpowiedź. Pomyślałem jednak o podjęciu trudu, jaki musiałem znieść, aby skrypt powłoki był uruchamiany z aplikacji Spring-Boot dla przyszłych programistów.
Pracowałem w Spring-Boot i nie mogłem znaleźć pliku do wykonania w mojej aplikacji Java i wyrzucał FileNotFoundFoundException
. Musiałem zachować plik w resources
katalogu i ustawić plik do skanowania pom.xml
podczas uruchamiania aplikacji, jak poniżej.
<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
. Następnie musiałem uczynić plik wykonywalnym, uruchamiając to polecenie -chmod u+x myShellScript.sh
Wreszcie mogłem uruchomić plik za pomocą następującego fragmentu kodu.
public void runScript() {
ProcessBuilder pb = new ProcessBuilder("src/main/resources/myFile.sh");
try {
Process p;
p = pb.start();
} catch (IOException e) {
e.printStackTrace();
}
}
Mam nadzieję, że to rozwiązuje czyjś problem.
do użytku w systemie 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);
}
}
i do użytku;
ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"});
LUB
ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"}, new Hashmap<>());