From Java I need to execute a user-installed command (let’s call it abc
) on macOS. However when running
Runtime.getRuntime().exec(new String[] {"abc", "--argument"});
it cannot be found as Java seems to inherit a limited system $PATH (it works when calling it from the system shell). I figured out
Runtime.getRuntime().exec(new String[] {"sh", "-c", "$SHELL -c 'abc --argument'"});
works on my device (tested with zsh and fish as shells). However on a different device that has bash set as the system shell, it cannot be found. I had hoped that calling $SHELL
would load the login path.
Both of these do not work:
Runtime.getRuntime().exec(cmd);
processBuilder.start();
What is the correct way to run a command in the System $PATH from Java?
Answers
When running a command from Java, it's important to ensure that the command is executed within the context of the correct environment, including the system $PATH
variable. Here are a few approaches you can try:
-
Use Absolute Path: Instead of relying on the system
$PATH
, you can specify the absolute path to the command in your Java code. This ensures that the command is found regardless of the environment's$PATH
settings.Runtime.getRuntime().exec("/path/to/abc --argument");
-
Modify
$PATH
Programmatically: You can modify the$PATH
variable programmatically within your Java code before executing the command. This ensures that the command is found in the modified$PATH
.String command = "abc --argument"; String[] env = {"PATH=/new/path:" + System.getenv("PATH")}; Runtime.getRuntime().exec(command, env);
-
Use
ProcessBuilder
with Inherited Environment:ProcessBuilder
provides a more flexible way to execute commands and allows you to inherit the environment of the current Java process. This ensures that the command is executed within the same environment as the Java process.ProcessBuilder pb = new ProcessBuilder("abc", "--argument"); pb.inheritIO(); // Inherit the I/O streams of the Java process pb.start();
-
Use Shell Invocation: If the command relies on shell-specific behavior (e.g., shell aliases, environment variables), you can invoke a shell and execute the command within it.
Runtime.getRuntime().exec(new String[] {"sh", "-c", "abc --argument"});
However, as you've noticed, this approach may not work consistently across different shell environments.
Choose the approach that best fits your requirements and the specific behavior of the command you're executing. If you're encountering issues with one approach, try another until you find one that works reliably across different environments.