ProcessBuilder in Java
The ProcessBuilder class in Java, in java.lang, is used to start an external program, such as a script, a command-line tool or another Java program, from inside your Java program. You give it the command and its arguments, and optionally a working directory and environment variables; it then starts a Process whose output you can read and whose exit code you can check. In this lesson, you will learn how to run a command, read its output, and handle errors.
Declaration
public final class ProcessBuilderMethods
| Method | Description |
|---|---|
new ProcessBuilder("cmd", "arg1", ...) | It is used to set the program and its arguments. |
directory(File dir) | It sets the working directory. |
environment() | It returns a modifiable map of environment variables. |
redirectErrorStream(true) | It merges error output into normal output. |
redirectOutput(File f) / inheritIO() | It sends output to a file, or to this program's console. |
start() | It starts the process and returns a Process. |
process.getInputStream() | It reads what the process prints. |
process.waitFor() | It waits for the process to finish and returns its exit code. |
process.waitFor(timeout, unit) | It waits at most a given time. |
Example: Running a Command and Reading Its Output
Let's see an example that runs the echo command, which exists on macOS and Linux. On Windows, the command would be new ProcessBuilder("cmd", "/c", "echo", ...).
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class RunEcho {
public static void main(String[] args)
throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("echo", "Hello from Navika");
pb.redirectErrorStream(true);
Process process = pb.start();
try (BufferedReader out = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = out.readLine()) != null) {
System.out.println("child said: " + line);
}
}
int exitCode = process.waitFor();
System.out.println("exit code: " + exitCode);
}
}child said: Hello from Navika
exit code: 0Explanation: Each part of the command is a separate argument; no shell is involved, so spaces inside "Hello from Navika" are kept as one argument. start() launches the program. Its output arrives through getInputStream() (it's "input" from Java's point of view). waitFor() returns the exit code; 0 means success.
Example: Exit Codes and Errors
import java.io.IOException;
public class ExitCodes {
public static void main(String[] args) throws InterruptedException {
try {
Process ok = new ProcessBuilder("true").start();
System.out.println("true exited with " + ok.waitFor());
Process fail = new ProcessBuilder("false").start();
System.out.println("false exited with " + fail.waitFor());
new ProcessBuilder("no-such-program-xyz").start();
} catch (IOException e) {
System.out.println("Could not start: "
+ e.getClass().getSimpleName());
}
}
}true exited with 0
false exited with 1
Could not start: IOExceptionExplanation: The Unix commands true and false do nothing except exit with 0 and 1. A program that doesn't exist can't be started, so start() throws IOException.
Security Note
Never build a command by joining user input into one string and running it through a shell (sh -c "..."). A user could add ; rm -rf ... to your command. Pass each argument separately to ProcessBuilder, which doesn't use a shell, and validate input first.
Common Mistakes
Passing the whole command as one string: new ProcessBuilder("ls -l"). It looks for a program literally named "ls -l"; split it: ("ls", "-l").
Not reading the output of a chatty process. It can block forever.
Ignoring the exit code. A non-zero code means the program failed.
Practice
- Easy: Run
java --versionwithProcessBuilderand print every line it outputs. - Harder: Run a command with
waitFor(2, TimeUnit.SECONDS), and calldestroy()on the process if it hasn't finished in time.
Key Takeaways
Was this tutorial helpful?