Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify PATH when launching Terminal from Java

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?

like image 690
Thomas S. Avatar asked Nov 07 '13 11:11

Thomas S.


People also ask

How do I change my Java home PATH?

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.


2 Answers

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).

like image 94
Ian Roberts Avatar answered Oct 16 '22 14:10

Ian Roberts


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?

like image 2
Pete Verdon Avatar answered Oct 16 '22 16:10

Pete Verdon