Week 129 — How can one create and start a new process?

Question of the Week #129
How can one create and start a new process?
6 Replies
Eric McIntyre
Eric McIntyre4mo ago
The JDK provides the ProcessBuilder to execute other programs. It is possible to create a ProcessBuilder by specifying the program and the arguments in the constructor. After optionally configuring the ProcessBuilder, the start() method can be used to start the process. For example, the following code runs ip route and prints the output to the console:
ProcessBuilder pb = new ProcessBuilder("ip", "route");
pb.inheritIO();//use System.out, System.in and System.err for stdout, stdin and stderr
Process process = pb.start();

// Wait for the command to complete
int statusCode = process.waitFor();
ProcessBuilder pb = new ProcessBuilder("ip", "route");
pb.inheritIO();//use System.out, System.in and System.err for stdout, stdin and stderr
Process process = pb.start();

// Wait for the command to complete
int statusCode = process.waitFor();
Instead of printing the routes to the console, the output can be accessed programmatically as well:
Process routeProcess = new ProcessBuilder("ip", "route").start();
try(BufferedReader br = new BufferedReader(new InputStreamReader(routeProcess.getInputStream(), StandardCharsets.UTF_8))){
long numOfRoutes = br.lines().count();
System.out.println(numOfRoutes + " routes (including default route)");
}
Process routeProcess = new ProcessBuilder("ip", "route").start();
try(BufferedReader br = new BufferedReader(new InputStreamReader(routeProcess.getInputStream(), StandardCharsets.UTF_8))){
long numOfRoutes = br.lines().count();
System.out.println(numOfRoutes + " routes (including default route)");
}
Or it can be written to a file:
new ProcessBuilder("ip", "route").redirectOutput(new File("routes.txt")).start().waitFor();
new ProcessBuilder("ip", "route").redirectOutput(new File("routes.txt")).start().waitFor();
In addition to configuring stdin/stdout/stderr, it also prvides methods for accessing environment variables and the working directory:
// list the files in /etc and print them to the console
new ProcessBuilder("ls")
.directory(new File("/etc"))
.inheritIO()
.start()
.waitFor();

// start a bash process printing some environment variable set in the application
ProcessBuilder pb = new ProcessBuilder("bash", "-c", "echo $SOME_ENV_VARIABLE");
Map<String, String> env = pb.environment();
env.put("SOME_ENV_VARIABLE", "Hello World");
pb
.inheritIO()
.start()
.waitFor();
// list the files in /etc and print them to the console
new ProcessBuilder("ls")
.directory(new File("/etc"))
.inheritIO()
.start()
.waitFor();

// start a bash process printing some environment variable set in the application
ProcessBuilder pb = new ProcessBuilder("bash", "-c", "echo $SOME_ENV_VARIABLE");
Map<String, String> env = pb.environment();
env.put("SOME_ENV_VARIABLE", "Hello World");
pb
.inheritIO()
.start()
.waitFor();
ProcessBuilder also provides a static method that can be used to compose multiple ProcessBuilders similar to the usage of the | operator in POSIX shells:
List<Process> processes = ProcessBuilder.startPipeline(
List.of(
new ProcessBuilder("ip", "route"),
new ProcessBuilder("grep", "^[0-9]"),
new ProcessBuilder("cut", "-d ", "-f9")
));
Process finalProcess = processes.getLast();
try(BufferedReader br = new BufferedReader(new InputStreamReader(finalProcess.getInputStream(), StandardCharsets.UTF_8))){
List<String> ips = br.lines().toList();
System.out.println(ips);
}
List<Process> processes = ProcessBuilder.startPipeline(
List.of(
new ProcessBuilder("ip", "route"),
new ProcessBuilder("grep", "^[0-9]"),
new ProcessBuilder("cut", "-d ", "-f9")
));
Process finalProcess = processes.getLast();
try(BufferedReader br = new BufferedReader(new InputStreamReader(finalProcess.getInputStream(), StandardCharsets.UTF_8))){
List<String> ips = br.lines().toList();
System.out.println(ips);
}
Eric McIntyre
Eric McIntyre4mo ago
Java also provides other mechanisms to start processes like Runtime#exec but these provide less control and can be harder to use when arguments may contain spaces or similar.
📖 Sample answer from dan1st
Eric McIntyre
Eric McIntyre4mo ago
Using ProcessBuilder class String command = "This is a process”; ProcessBuilder pb = new ProcessBuilder(command); Process process = pb.start()
Eric McIntyre
Eric McIntyre4mo ago
;
Submission from riti0710
Eric McIntyre
Eric McIntyre4mo ago
To start a new process in java, you can use either the ProcessBuilder class or the Runtime.exec() method. Both methods allow you to create and start a new process from your program, but ProcessBuilder is more flexible and preferred for most use cases. ProcessBuilder Approach
ProcessBuilder pb = new ProcessBuilder("echo", "Hello World!");
Process process = pb.start();
ProcessBuilder pb = new ProcessBuilder("echo", "Hello World!");
Process process = pb.start();
Similarly, you can set the process environment and redirect its input/output streams with something like this:
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "echo $horse $dog $HOME");
pb.environment().put("horse", "Imagine");
pb.environment().put("dog", "NoDogs");
Process process = pb.start();
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "echo $horse $dog $HOME");
pb.environment().put("horse", "Imagine");
pb.environment().put("dog", "NoDogs");
Process process = pb.start();
ProcessBuilder pb = new ProcessBuilder("java", "-version");
pb.redirectErrorStream(true);
File log = new File("java-version.log");
pb.redirectOutput(log);
Process process = pb.start();
ProcessBuilder pb = new ProcessBuilder("java", "-version");
pb.redirectErrorStream(true);
File log = new File("java-version.log");
pb.redirectOutput(log);
Process process = pb.start();
Runtime.exec() Approach
Process process = Runtime.getRuntime().exec("echo Hello World!");
Process process = Runtime.getRuntime().exec("echo Hello World!");
This method also returns a Process object similar to ProcessBuilder, but is less flexible compared to ProcessBuilder. (e.g. environment customization and I/O redirection are less convenient). ---------------- Both enlisted approachs return a Process object, which provides methods to: - Read the process’s output (getInputStream()) - Write to the process’s input (getOutputStream()) - Read the process’s error stream (getErrorStream()) - Wait for the process to finish (waitFor()) - Get the exit code (exitValue()) - Destroy the process (destroy()) NOTE: Name of methods getInputStream() and getOutputStream() may feel counterintuitive as they are named from the perspective of the java program, not the external process. getInputStream() returns InputStream which essentially means Output of Program -> Java and getOutputStream() returns OutputStream which means Java -> Input of Program.
Eric McIntyre
Eric McIntyre4mo ago
Practically, you'd always want to ProcessBuilder as it's more configurable. You'd only see and use Runtime.exec() for simpler cases or while maintaining legacy code prior to Java 5.
ProcessBuilder pb = new ProcessBuilder("ping", "-c", "4", "google.com");
Process process = pb.start();
InputStream is = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
process.waitFor();
ProcessBuilder pb = new ProcessBuilder("ping", "-c", "4", "google.com");
Process process = pb.start();
InputStream is = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
process.waitFor();
⭐ Submission from daysling

Did you find this page helpful?