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.

EDIT

You should also consider to hide the complexity of the process builder behind a simple interface.

Separate what you need (the interface) from how it is done (the implementation).

public interface FileUtils {
    public String[] listFiles(String dirpath);
}

You can then provide implementations that use the process builder or maybe native methods to do the job and you can provide different implementations for different environments like linux or windows.

Finally such an interface is also easier to mock in unit tests.

Answer from René Link on Stack Overflow
Top answer
1 of 8
30

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.

EDIT

You should also consider to hide the complexity of the process builder behind a simple interface.

Separate what you need (the interface) from how it is done (the implementation).

public interface FileUtils {
    public String[] listFiles(String dirpath);
}

You can then provide implementations that use the process builder or maybe native methods to do the job and you can provide different implementations for different environments like linux or windows.

Finally such an interface is also easier to mock in unit tests.

2 of 8
12

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;
}
🌐
Baeldung
baeldung.com › home › java › core java › how to run a shell command in java
How to Run a Shell Command in Java | Baeldung
January 8, 2024 - ProcessBuilder builder = new ProcessBuilder(); if (isWindows) { builder.command("cmd.exe", "/c", "dir"); } else { builder.command("sh", "-c", "ls"); } builder.directory(new File(System.getProperty("user.home"))); Process process = builder.start(); StreamGobbler streamGobbler = new StreamGobbler(process.getInputStream(), System.out::println); Future<?> future = executorService.submit(streamGobbler); int exitCode = process.waitFor(); assertDoesNotThrow(() -> future.get(10, TimeUnit.SECONDS)); assertEquals(0, exitCode); Java 9 introduced the concept of pipelines to the ProcessBuilder API:
🌐
Medium
frankielc.medium.com › run-bash-commands-from-java-8319fbff23f7
Run bash commands from Java - Frankie - Medium
March 1, 2023 - As one of Java paradigms is “write once, run anywhere”, and calling external software makes that much more complicated, you’ll want to steer away from it as much as possible. However, sometimes there’s really no other viable option. The example below shows how to ping a host and capture both the standard and the error output streams. String cmd = "ping -c 4 -W 1 8.8.8.8" try { ProcessBuilder pb = new ProcessBuilder("bash", "-c", cmd); pb.redirectErrorStream(true); Process process = pb.start(); process.waitFor(10, TimeUnit.SECONDS); try (BufferedReader br = new BufferedReader( new Input
🌐
Stack Abuse
stackabuse.com › executing-shell-commands-with-java
Executing Shell Commands with Java
May 18, 2020 - In this tutorial, we'll cover how to execute shell commands, bat and sh files in Java. We'll be covering examples for all exec() and ProcessBuilder approaches.
🌐
Mkyong
mkyong.com › home › java › how to execute shell command from java
How to execute shell command from Java - Mkyong.com
January 3, 2019 - I really like your articles on Java. For this one i guess i could not do as mentioned. I googled and figured out that you need to first connect to the linux box from java and then you can execute shell commands.
🌐
ExtraVM
thishosting.rocks › how-to-execute-a-shell-command-using-java
How To Execute a Shell Command Using Java
May 19, 2021 - Runtime.exec() is a simple high-level class, not customizable at the moment but available in every Java application. It gives the possibility for the application to communicate within its environment. The exec() method is for executing commands ...
🌐
GeeksforGeeks
geeksforgeeks.org › java › how-to-execute-native-shell-commands-from-java-program
How to Execute Native Shell Commands from Java Program? - GeeksforGeeks
March 3, 2021 - We use a list to build commands and then execute them using the "start" method of the ProcessBuilder class. The program runs the command to find the chrome browser processes from the tasklist running in the machine. ... // Run a simple Windows shell command import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; public class ShellCommandRunner { public static void main(String[] args) { ProcessBuilder processBuilder = new ProcessBuilder(); List<String> builderList = new ArrayList<>(); // add the list of comm
Find elsewhere
🌐
GitHub
gist.github.com › 4283217
Executing a linux bash command from a java program and reading the response of it which spans multiple lines · GitHub
Executing a linux bash command from a java program and reading the response of it which spans multiple lines
🌐
Stack Exchange
unix.stackexchange.com › questions › 237104 › how-to-run-java-program-in-bash-script-and-give-it-one-argument
directory - How to run Java program in Bash script and give it one argument? - Unix & Linux Stack Exchange
October 19, 2015 - I know about that Java thingy., in fact, it's not about Java - but how to make the OS, run a program, in a way that I want, with all requirements supplied. ... There is Caja-actions Configration tool to add the open with ABC in context menu. There is command tab in Caja Action tool, there you can provide the script path and the directory argument.
🌐
YouTube
youtube.com › watch
Run Bash Command On Remote Machine From Java - YouTube
In this video I showed how you run command or bash script from java applicationcode : https://github.com/lynas/bash-command-remote-machine-javaother videos: ...
Published   November 23, 2018
🌐
Blogger
javarevisited.blogspot.com › 2011 › 02 › how-to-execute-native-shell-commands.html
How to Execute Native Shell commands from Java Program? Example
How to execute native shell commands from JAVA Though it’s not recommended some time it’s become necessary to execute a native operating system or shell command from Java, especially if you are doing some kind of reporting or monitoring stuff and required information can easily be found using the native command.
🌐
Netjstech
netjstech.com › 2016 › 10 › how-to-run-shell-script-from-java-program.html
How to Run a Shell Script From Java Program | Tech Tutorials
You can't just rum a sh file from windows command line. Delete ... If you are using Windows replace "sh" with "cmd". The terminal of is "powershell" or "cmd". "sh", "/bin/bash", "/usr/bin/python" for other kinds of scripts.ReplyDelete ... This method works fine when I try to execute on local.
🌐
Kevin Boone
kevinboone.me › exec.html
How to run a shell script from a Java application - Kevin Boone
That is, the kernel can actually ... on. To invoke the shell to run the script, we might try something like this: ... The -c switch tells the shell to process the next argument as a command....
🌐
DZone
dzone.com › coding › languages › execute shell command from java
Execute Shell Command From Java
August 14, 2008 - String cmd = "ls -al"; Runtime run = Runtime.getRuntime(); Process pr = run.exec(cmd); pr.waitFor(); BufferedReader buf = new BufferedReader(new...
Top answer
1 of 2
2

When you invoke a command in Unix, you provide a sequence of "words". These are not processed or reinterpreted at all; the first word is the command to invoke and the remaining words are its arguments. (In a Dockerfile, compare to the JSON-array exec-form syntax of CMD.)

In your examples, you're trying to mix this string-array syntax with shell constructs. If you try to run "bash", "foo", "&&", "bar", then it will specifically use bash as an interpreter to run foo as a shell script, passing it two arguments && and bar. In your very first example you use sh -c passing the rest of the command as a single argument. This has the right effect, but it makes you vulnerable to a shell injection attack if, for example, the folder name includes a semicolon.

String folder = "; rm -rf /;";
// uh oh
Runtime.getRuntime().exec(new String[]{"bash", "-c", "cd " + folder + "&& ..."});

All of your commands are of the form cd directory && command. You can use ProcessBuilder.directory() to set the directory name, and then directly run command without actually involving a shell. This both solves your problem and the security issue.

Process process = new ProcessBuilder()
  .directory(new File("/home/alex/IdeaProjects/test/src/main/java/Docker"))
  .command("docker", "build", " -f", "Dockerfile.txt", "-t", "java-app1", ".")
  .start();

The actual right answer to this is to use a Docker SDK rather than invoke the docker CLI tool. Using docker-java, for example, you might write

DockerClientConfig standard = DefaultDockerClientConfig
  .createDefaultConfigBuilder()
  .build();
DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder()
  .dockerHost(config.getDockerHost())
  .sslConfig(config.getSSLConfig())
  .build();
DockerClient dockerClient = DockerClientImpl.getInstance(config, httpClient);

dockerClient.buildImageCmd()
  .withBaseDirectory(new File("/home/alex/IdeaProjects/test/src/main/java/Docker"))
  .withDockerfilePath("Dockerfile.txt")
  .withTags(Set.of("java-app1"))
  .start();
// ...and wait for its completion

Remember in any case that, if you can access the Docker socket at all, then you can launch a new container, running as root, bind-mounting the host filesystem, and take over the whole machine.

2 of 2
-3

try to add "/c" at the end of your string, it use to start the command you refer.