wake-up-neo.net

Wie kann ich ein Unix-Shell-Skript mit Java-Code ausführen?

Es ist ziemlich einfach, einen Unix-Befehl von Java aus auszuführen. 

Runtime.getRuntime().exec(myCommand);

Aber ist es möglich, ein Unix-Shell-Skript mit Java-Code auszuführen? Wenn ja, wäre es eine gute Praxis, ein Shell-Skript aus Java-Code heraus auszuführen?

139
Vicky

Sie sollten sich wirklich unter Process Builder . Es ist wirklich für so etwas gebaut.

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();
169
Milhous

Ich würde sagen, dass es nicht im Sinne von Java ist, ein Shell-Skript von Java aus auszuführen. Java soll plattformübergreifend sein, und die Verwendung eines Shell-Skripts würde seine Verwendung auf UNIX beschränken.

Damit ist es auf jeden Fall möglich, ein Shell-Skript in Java auszuführen. Sie würden genau die gleiche Syntax verwenden, die Sie aufgelistet haben (ich habe es selbst nicht versucht, versuchen Sie jedoch, das Shell-Skript direkt auszuführen. Wenn dies nicht funktioniert, führen Sie die Shell selbst aus, und übergeben Sie das Skript als Befehlszeilenparameter.) .

23
Jack Leow

Ich glaube, du hast deine eigene Frage mit beantwortet

Runtime.getRuntime().exec(myShellScript);

Ob es sich dabei um eine bewährte Vorgehensweise handelt ... Was versuchen Sie mit einem Shell-Skript, das Sie mit Java nicht tun können?

21
Chris Ballance

Sie können auch Apache Commons exec library verwenden.

Beispiel:

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");
    }
}

Ein weiteres Beispiel finden Sie auf Apache Doc .

20
Not a bug

Ja, das ist möglich. Das hat für mich geklappt.

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());
        }
    }

Hier ist mein Beispiel. Ich hoffe es macht Sinn.

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(this.isLinux()){
        Runtime.getRuntime().exec(new String[] {"/bin/sh", "-c", filePath}, null);
    }else if(this.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;
}
4
Lionel Yan

Die ZT Process Executor Bibliothek ist eine Alternative zu Apache Commons Exec. Es verfügt über Funktionen zum Ausführen von Befehlen, Erfassen der Ausgabe, Einstellen von Zeitüberschreitungen usw.

Ich habe es noch nicht benutzt, aber es sieht einigermaßen gut dokumentiert aus.

Ein Beispiel aus der Dokumentation: Ausführen eines Befehls, Pumpen des stderr zu einem Logger, Zurückgeben der Ausgabe als UTF8-String.

 String output = new ProcessExecutor().command("Java", "-version")
    .redirectError(Slf4jStream.of(getClass()).asInfo())
    .readOutput(true).execute()
    .outputUTF8();

Seine Dokumentation listet die folgenden Vorteile gegenüber Commons Exec auf:

  • Verbesserte Handhabung von Streams
    • Lesen/Schreiben in Streams
    • Stderr nach stdout umleiten
  • Verbesserte Behandlung von Timeouts
  • Verbesserte Überprüfung der Beendigungscodes
  • Verbesserte API
    • Ein Liner für recht komplexe Anwendungsfälle
    • Ein Liner, um die Prozessausgabe in einen String zu bekommen
    • Zugriff auf das Process Objekt verfügbar
    • Unterstützung für asynchrone Prozesse (Future
  • Verbesserte Protokollierung mit SLF4J API
  • Unterstützung für mehrere Prozesse
3
Lii

Ja, es ist möglich und du hast es beantwortet! Ich denke, es ist besser, wenn Sie Befehle aus Dateien und nicht direkt aus Ihrem Code heraus starten. Daher muss Java die Befehlsliste (oder einen Befehl) in einer vorhandenen .bat-, .sh-, .ksh-Datei ausführen. Hier ein Beispiel zum Ausführen einer Liste von Befehlen in einer Datei "MyFile.sh":

    String[] cmd = { "sh", "MyFile.sh", "\pathOfTheFile"};
    Runtime.getRuntime().exec(cmd);
3
YANKEE

Um zu vermeiden, dass ein absoluter Pfad hardcodiert werden muss, können Sie die folgende Methode verwenden, die Ihr Skript findet und ausführt, wenn es sich in Ihrem Stammverzeichnis befindet.

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!");
    }
}
2
anataliocs

Für mich müssen alle Dinge einfach sein. Zum Ausführen eines Skripts muss es nur ausgeführt werden

new ProcessBuilder("pathToYourShellScript").start();
2
Vladimir Bosyi

Es ist möglich, es wie jedes andere Programm auszuführen. Stellen Sie einfach sicher, dass Ihr Skript die richtige # hat! (she-bang) Zeile als erste Zeile des Skripts und vergewissern Sie sich, dass die Datei Ausführungsberechtigungen hat.

Wenn es sich beispielsweise um ein Bash-Skript handelt, setzen Sie #!/Bin/bash oben im Skript, auch chmod + x.

Auch wenn es sich um eine bewährte Vorgehensweise handelt, ist dies nicht der Fall, insbesondere für Java. Wenn Sie jedoch Zeit sparen, wenn Sie ein umfangreiches Skript portieren, werden Sie dafür nicht extra bezahlt;) Sparen Sie Zeit Skript und fügen Sie die Portierung nach Java in Ihre langfristige Aufgabenliste ein.

1
Kekoa
  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();
  }  

Dies ist eine späte Antwort. Ich überlegte mir jedoch, ob ich mich bemühen sollte, ein Shell-Skript aus einer Spring-Boot-Anwendung für zukünftige Entwickler auszuführen. 

  1. Ich arbeitete in Spring-Boot und konnte die aus meiner Java-Anwendung auszuführende Datei nicht finden, und es gab FileNotFoundFoundException. Ich musste die Datei im Verzeichnis resources aufbewahren und die zu scannende Datei in pom.xml festlegen, während die Anwendung wie folgt gestartet wurde. 

    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*.xml</include>
                <include>**/*.properties</include>
                <include>**/*.sh</include>
            </includes>
        </resource>
    </resources>
    
  2. Danach hatte ich Probleme beim Ausführen der Datei und es wurde error code = 13, Permission Denied zurückgegeben. Dann musste ich die Datei durch Ausführen dieses Befehls ausführbar machen - chmod u+x myShellScript.sh 

Schließlich konnte ich die Datei mit dem folgenden Code-Snippet ausführen. 

public void runScript() {
    ProcessBuilder pb = new ProcessBuilder("src/main/resources/myFile.sh");
    try {
        Process p;
        p = pb.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Hoffe das löst jemandes Problem. 

1
Reaz Murshed

Hier ein Beispiel, wie Sie ein Unix-Bash oder Windows-Bat/cmd-Skript von Java aus ausführen. Argumente können an das Skript übergeben und die vom Skript empfangenen Ausgaben ausgegeben werden. Die Methode akzeptiert eine beliebige Anzahl von Argumenten.

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);
    }
}

Wenn Sie unter Unix/Linux laufen, muss der Pfad Unix-ähnlich sein (mit '/' als Trennzeichen). Wenn Sie unter Windows laufen, verwenden Sie '\'. Hier ist ein Beispiel für ein Bash-Skript (test.sh), das eine beliebige Anzahl von Argumenten empfängt und jedes Argument verdoppelt:

#!/bin/bash
counter=0
while [ $# -gt 0 ]
do
  echo argument $((counter +=1)): $1
  echo doubling argument $((counter)): $(($1+$1))
  shift
done

Beim anrufen 

runScript("path_to_script/test.sh", "1", "2")

unter Unix/Linux lautet die Ausgabe:

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 ist ein einfaches cmd-Windows-Skript test.cmd, das die Anzahl der Eingabeargumente zählt:

@echo off
set a=0
for %%x in (%*) do Set /A a+=1 
echo %a% arguments received

Beim Aufruf des Skripts unter Windows

  runScript("path_to_script\\test.cmd", "1", "2", "3")

Die Ausgabe ist

Received from script: 3 arguments received

für Linux verwenden

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);
    }
}

und zur Verwendung;

ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"});

OR

ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"}, new Hashmap<>());
0
Ali Bagheri

Genau wie bei Solaris 5.10 funktioniert es so ./batchstart.sh Es gibt einen Trick, von dem ich nicht weiß, ob Ihr Betriebssystem es akzeptiert, stattdessen \\. batchstart.sh zu verwenden. Dieser doppelte Schrägstrich kann helfen.

0
Saul

Ich denke mit

System.getProperty("os.name"); 

Wenn das Betriebssystem aktiviert ist, kann das Shell/bash-Skript verwaltet werden, sofern ein solches unterstützt wird.

0
DayaMoon