Open Terminal Window with Predefined Environment Variables (Including `PATH`)

bashenvironment-variablesfinderterminal

I'm trying to create a .command file which will open a terminal window with predefined Environment Variables (Including PATH).

I tried this:

#!/bin/bash

# Adding CMake to Path
export PATH=$PATH:/Users/Shared/CMake/CMake.app/Contents/bin/:

# Adding Ninja to Path
export PATH=$PATH:/Users/Shared/Ninja/:

# Adding GCC to Path
export PATH=$PATH:/usr/local/gcc-8.2/bin/:

echo Path Updated

Yet when I double click on Finder I get this:

Path Updated
logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.
Deleting expired sessions...none found.

[Process completed]

Namely it is gone.

Is the a way to have a file which does the following (Maybe it has to be 2 different files, I don't know):

  1. If clicked from finder will open a new terminal window with all the variables defined / updated (Including the PATH).
  2. If run from terminal will update the current terminal state.

Any idea?

Best Answer

You need to explicitly start an interactive bash shell at the end of your script in order to keep the window open when you open the .command file from Finder.

The following revision of your script demonstrates that and also streamlines other aspects of your code:

#!/bin/bash

# Note: $PATH already exists as an exported variable, assigning to it
#       again preserves that status, so there's no need to call `export` below.

# Adding CMake to Path
PATH+=:/Users/Shared/CMake/CMake.app/Contents/bin/

# Adding Ninja to Path
PATH+=:/Users/Shared/Ninja/

# Adding GCC to Path
PATH+=:/usr/local/gcc-8.2/bin/

cat <<EOF
Path updated to:

  $PATH

Starting interactive Bash shell...
EOF

# Start an interactive Bash shell that inherits this script's environment
# and keeps the window open.
# Using -l makes the interactive shell a login shell, which makes it
# load the same initialization files as shells created by Terminal.app,
# notably, ~/.bash_profile
# Be sure that ~/.bash_profile doesn't override $PATH.
exec bash -l

This .command file will also from an existing terminal window, but note that you will enter an interactive child shell - exiting from that child shell will return to you to the original one.


It is possible to amend your script so that if you invoke it from an existing terminal window (shell), it modifies that shell's environment directly, but you then have to source / . the script on invocation (e.g., . ./script.command):

#!/bin/bash

# Note: $PATH already exists as an exported variable, assigning to it
#       again preserves that status, so there's no need to call `export` below.

# Adding CMake to Path
PATH+=:/Users/Shared/CMake/CMake.app/Contents/bin/

# Adding Ninja to Path
PATH+=:/Users/Shared/Ninja/

# Adding GCC to Path
PATH+=:/usr/local/gcc-8.2/bin/

# Determine if this script is being sourced.
[[ $0 != "$BASH_SOURCE" ]] && sourced=1 || sourced=0

cat <<EOF
Path updated to:

  $PATH

EOF

if (( sourced )); then # sourced from the calling shell.
  # The calling shell's environment has been modified - nothing more to do.
  :
else # otherwise: launched from Finder or from a terminal without sourcing
  # A new interactive shell must be launched for the environment modifications
  # to take effect and, if launched from Finder, to keep the terminal window
  # open.
  echo "Starting new interactive Bash shell with modified environment..."
  # Using -l makes the interactive shell a login shell, which makes it
  # load the same initialization files as shells created by Terminal.app,
  # notably, ~/.bash_profile
  # Be sure that ~/.bash_profile doesn't override $PATH.
  exec bash -l
fi