Running Bash commands in Java

我是研究僧i 提交于 2019-11-27 12:52:49

You start a new process with Runtime.exec(command). Each process has a working directory. This is normally the directory in which the parent process was started, but you can change the directory in which your process is started.

I would recommend to use ProcessBuilder

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

If you want to run multiple commands in a shell it would be better to create a temporary shell script and run this.

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

Of course you can also use any other script on your system. Generating a script at runtime makes sometimes sense, e.g. if the commands that are executed have to change. But you should first try to create one script that you can call with arguments instead of generating it dynamically at runtime.

It might also be reasonable to use a template engine like velocity if the script generation is complex.

You can form one complex bash command that does everything: "ls; cd bin; ls". To make this work you need to explicitly invoke bash. This approach should give you all the power of the bash command line (quote handling, $ expansion, pipes, etc.).

/**
 * 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;
}

Each invocation executes in it's own shell. Thus the "cd" of the 2nd invocation is not seen by the third.

See: https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#exec(java.lang.String).

This states that the command is run in a separate process. Thus you have spawned 3 processes.

If you want all 3 in the same process, try this:

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

each command you are running has its own bash shell, so once you cd to that directory and for next command you are opening new bash shell

try changing your command to

ls bin

Each command is executed individually. They dont share the context.

for future reference: running bash commands after cd , in a subdirectory:

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

You could use the bash command "pmset -g batt" like in the method bellow witch returns the battery percentage

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('%')));
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!