I use following Java code to launch a Terminal:
final ProcessBuilder processBuilder = new ProcessBuilder("/usr/bin/open", "-b",
"com.apple.Terminal",
"/Volumes");
final Map<String, String> environment = processBuilder.environment();
final String path = environment.get("PATH");
environment.put("PATH", "/mypath" + File.pathSeparator + path);
final Process process = processBuilder.start();
process.waitFor();
This causes a terminal window to be opened, but the modifications of PATH seem to be ignored:
Volumes$ echo $PATH
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
This problem seems to be related to how I'm launching the Terminal. Launching other applications with modifying the environment variables works fine.
How to launch the Terminal so that it accepts my environment variable modifications, even if the Terminal already is open?
To set JAVA_HOME, do the following: Right click My Computer and select Properties. On the Advanced tab, select Environment Variables, and then edit JAVA_HOME to point to where the JDK software is located, for example, C:\Program Files\Java\jdk1. 6.0_02.
In this particular case you could fake it by using AppleScript to open the terminal:
final ProcessBuilder processBuilder = new ProcessBuilder(
"/usr/bin/osascript", "-e");
final Map<String, String> environment = processBuilder.environment();
final String path = environment.get("PATH");
processBuilder.command().add("tell application \"Terminal\" to do script \"" +
"cd /Volumes ; export PATH=\\\"/mypath:" + path + "\\\\"\"");
final Process process = processBuilder.start();
process.waitFor();
If you want to populate the cd
directory and the PATH
value from user-supplied parameters then I would consider using on run
to let the script take arguments, and use quoted form of
to avoid any potential issues with quoting:
final ProcessBuilder processBuilder = new ProcessBuilder("/usr/bin/osascript",
"-e", "on run argv",
"-e", " tell application \"Terminal\" to do script "
+ "\"cd \" & quoted form of item 1 of argv & \" ; "
+ "export PATH=\" & quoted form of item 2 of argv",
"-e", "end run");
// create a File and use getAbsolutePath to resolve any relative paths
// against this Java process's working directory.
File cdDir = new File(dirParam);
// this argument will be "item 1 of argv" to the AppleScript
processBuilder.command().add(cdDir.getAbsolutePath());
final Map<String, String> environment = processBuilder.environment();
final String path = environment.get("PATH");
File pathPrefix = new File(pathParam);
// and this will be "item 2 of argv"
processBuilder.command().add(
pathPrefix.getAbsolutePath() + File.pathSeparator + path);
final Process process = processBuilder.start();
process.waitFor();
If you can't do the getAbsolutePath
trick on the Java side but still want relative paths (relative to the current directory of osascript
) to work, then you'd need a trick like this:
final ProcessBuilder processBuilder = new ProcessBuilder("/usr/bin/osascript",
"-e", "on run argv",
"-e", " set currentdir to (do shell script \"pwd\")",
"-e", " set currentpath to (do shell script \"echo $PATH\")",
"-e", " tell application \"Terminal\" to do script \""
+ "cd \" & quoted form of currentdir & \" ; ""
+ "cd \" & quoted form of item 1 of argv & \" ; "
+ "export PATH=\" & quoted form of currentpath",
"-e", "end run",
dirParam);
final Map<String, String> environment = processBuilder.environment();
final String path = environment.get("PATH");
environment.put("PATH", pathParam + File.pathSeparator + path);
final Process process = processBuilder.start();
process.waitFor();
This is a bit of a Russian doll - we're executing osascript
from Java, which in turn runs its own subshell to do pwd
and echo $PATH
to get the values of the current working directory and the PATH
variable of the osascript process into AppleScript variables, which we then inject into the new Terminal. By first doing a cd
to the "current" dir, and then another cd
to the specified dirParam
this will handle both relative and absolute paths.
Finally note that osascript
prints the return value of the script, so you should make sure you consume all the process output before doing waitFor
(or if you're on Java 7 you can use processBuilder.redirectOutput(new File("/dev/null"))
and the same for redirectError
).
A couple of thoughts - I can't try anything out as I only have Linux at work.
You're opening the terminal via the open
command. Perhaps if you run the terminal executable directly (I guess you need to go to the actual binary inside the .app folder) your environment settings would pass through?
Alternatively, another way of starting the terminal is to open
a saved Terminal preferences file (extension .terminal, created via the Preferences panel of Terminal.app). This opens a Terminal with those preferences set. I haven't tinkered with Terminal preferences for years, but perhaps there's a way to set the path in there?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With