it-swarm.com.de

Java - Ausführen von Bash-Befehlen

Ich habe die folgende Klasse. Es erlaubt mir, Befehle über Java auszuführen.

public class ExecuteShellCommand {

public String executeCommand(String command) {

    StringBuffer output = new StringBuffer();

    Process p;
    try {
        p = Runtime.getRuntime().exec(command);
        p.waitFor();
        BufferedReader reader = 
                        new BufferedReader(new InputStreamReader(p.getInputStream()));

        String line = "";           
        while ((line = reader.readLine())!= null) {
            output.append(line + "\n");
        }

    } catch (Exception e) {
        e.printStackTrace();
    }

    return output.toString();

}

}

Wenn ich Befehle ausführe, wird das Ergebnis des vorherigen Befehls nicht gespeichert. Zum Beispiel:

public static void main(String args[]) {

    ExecuteShellCommand com = new ExecuteShellCommand();
    System.out.println(com.executeCommand("ls"));
    System.out.println(com.executeCommand("cd bin"));
    System.out.println(com.executeCommand("ls"));

}

Gibt die Ausgabe aus:

bin
src


bin
src

Warum zeigt der zweite Befehl 'ls' nicht den Inhalt des 'bin'-Verzeichnisses an?

14
mickzer

Sie starten einen neuen Prozess mit Runtime.exec(command). Jeder Prozess hat ein Arbeitsverzeichnis. Dies ist normalerweise das Verzeichnis, in dem der übergeordnete Prozess gestartet wurde. Sie können jedoch das Verzeichnis ändern, in dem Ihr Prozess gestartet wird.

Ich würde empfehlen, ProcessBuilder zu verwenden. 

ProcessBuilder pb = new ProcessBuilder("ls");
pb.inheritIO();
pb.directory(new File("bin"));
pb.start();

Wenn Sie mehrere Befehle in einer Shell ausführen möchten, sollten Sie ein temporäres Shell-Skript erstellen und dieses ausführen.

public void executeCommands() throws IOException {

    File tempScript = createTempScript();

    try {
        ProcessBuilder pb = new ProcessBuilder("bash", tempScript.toString());
        pb.inheritIO();
        Process process = pb.start();
        process.waitFor();
    } finally {
        tempScript.delete();
    }
}

public File createTempScript() throws IOException {
    File tempScript = File.createTempFile("script", null);

    Writer streamWriter = new OutputStreamWriter(new FileOutputStream(
            tempScript));
    PrintWriter printWriter = new PrintWriter(streamWriter);

    printWriter.println("#!/bin/bash");
    printWriter.println("cd bin");
    printWriter.println("ls");

    printWriter.close();

    return tempScript;
}

Natürlich können Sie auch jedes andere Skript auf Ihrem System verwenden. Das Generieren eines Skripts zur Laufzeit ist manchmal sinnvoll, z. wenn sich die ausgeführten Befehle ändern müssen. Sie sollten jedoch zunächst versuchen, ein Skript zu erstellen, das Sie mit Argumenten aufrufen können, anstatt es zur Laufzeit dynamisch zu generieren.

Es kann auch sinnvoll sein, eine Template-Engine wie Velocity zu verwenden, wenn die Skriptgenerierung komplex ist.

15
René Link

Jeder Aufruf wird in einer eigenen Shell ausgeführt. Daher wird die "CD" des zweiten Aufrufs vom dritten nicht gesehen.

Siehe: https://docs.Oracle.com/javase/7/docs/api/Java/lang/Runtime.html#exec(Java.lang.String) .

Dies besagt, dass der Befehl in einem separaten Prozess ausgeführt wird. So haben Sie 3 Prozesse hervorgebracht.

Wenn Sie alle 3 in demselben Prozess haben möchten, versuchen Sie Folgendes:

com.executeCommand("ls; cd bin; ls");
3
EJK

Sie können einen komplexen Bash-Befehl bilden, der alles ausführt: "ls; cd bin; ls". Damit dies funktioniert, müssen Sie explizit bash aufrufen. Dieser Ansatz sollte Ihnen die volle Leistungsfähigkeit der bash-Befehlszeile (Zitierweise, $ -Erweiterung, Pipes usw.) verleihen. 

/**
 * Execute a bash command. We can handle complex bash commands including
 * multiple executions (; | && ||), quotes, expansions ($), escapes (\), e.g.:
 *     "cd /abc/def; mv ghi 'older ghi '$(whoami)"
 * @param command
 * @return true if bash got started, but your command may have failed.
 */
public static boolean executeBashCommand(String command) {
    boolean success = false;
    System.out.println("Executing BASH command:\n   " + command);
    Runtime r = Runtime.getRuntime();
    // Use bash -c so we can handle things like multi commands separated by ; and
    // things like quotes, $, |, and \. My tests show that command comes as
    // one argument to bash, so we do not need to quote it to make it one thing.
    // Also, exec may object if it does not have an executable file as the first thing,
    // so having bash here makes it happy provided bash is installed and in path.
    String[] commands = {"bash", "-c", command};
    try {
        Process p = r.exec(commands);

        p.waitFor();
        BufferedReader b = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line = "";

        while ((line = b.readLine()) != null) {
            System.out.println(line);
        }

        b.close();
        success = true;
    } catch (Exception e) {
        System.err.println("Failed to execute bash with command: " + command);
        e.printStackTrace();
    }
    return success;
}
3
Steve Zobell

jeder Befehl, den Sie ausführen, hat eine eigene Bash-Shell. Wenn Sie also in dieses Verzeichnis wechseln, öffnen Sie für den nächsten Befehl die neue Bash-Shell 

versuchen Sie, Ihren Befehl in zu ändern

ls bin
2
Jigar Joshi

Jeder Befehl wird einzeln ausgeführt. Sie teilen den Kontext nicht. 

1
vatsal

als zukünftige Referenz: Ausführen von bash-Befehlen nach cd in einem Unterverzeichnis:

import Java.io.BufferedReader;
import Java.io.InputStreamReader;

/*

$ ( D=somewhere/else ; mkdir -p $D ; cd $D ; touch file1 file2 ; )
$ javac BashCdTest.Java && Java BashCdTest
 .. stdout: -rw-r--r-- 1 ubuntu ubuntu 0 Dec 28 12:47 file1
 .. stdout: -rw-r--r-- 1 ubuntu ubuntu 0 Dec 28 12:47 file2
 .. stderr: /bin/ls: cannot access isnt_there: No such file or directory
 .. exit code:2

*/
class BashCdTest
    {
    static void execCommand(String[] commandArr)
        {
        String line;
        try
            {
            Process p = Runtime.getRuntime().exec(commandArr);
            BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
            while ((line = stdoutReader.readLine()) != null) {
                // process procs standard output here
                System.out.println(" .. stdout: "+line);
                }
            BufferedReader stderrReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            while ((line = stderrReader.readLine()) != null) {
                // process procs standard error here
                System.err.println(" .. stderr: "+line);
                }
            int retValue = p.waitFor();
            System.out.println(" .. exit code:"+Integer.toString(retValue));
            }
        catch(Exception e)
            { System.err.println(e.toString()); }
        }

    public static void main(String[] args)
        {
        String flist = "file1 file2 isnt_there";
        String outputDir = "./somewhere/else";
        String[] cmd = {
            "/bin/bash", "-c",
            "cd "+outputDir+" && /bin/ls -l "+flist+" && /bin/rm "+flist
            };
        execCommand(cmd);
        }
    }
0
jmullee

Sie können den Bash-Befehl "pmset -g batt" wie in der unten beschriebenen Methode verwenden, die den Batterieprozentsatz zurückgibt 

public int getPercentage() {
    Process process = null;
    try {
        process = Runtime.getRuntime().exec("pmset -g batt");
    } catch (IOException e) {
        e.printStackTrace();
    }
    BufferedReader reader = new BufferedReader(new InputStreamReader(
            process.getInputStream()));
    String s = null;
    String y = "";
    while (true) {
        try {
            if (!((s = reader.readLine()) != null)) break;
        } catch (IOException e) {
            e.printStackTrace();
        }
        y += s;
        System.out.println("Script output: " + s);
    }
    return Integer.parseInt(y.substring(y.indexOf(')') + 2, y.indexOf('%')));
}
0
Naveen hut