Skip to content

Using a Shell Configuration File

Mark Birbeck edited this page Feb 12, 2015 · 2 revisions

Background

When shells run they don't always execute a user's profile scripts. If a shell is a login shell (i.e., the first one that is run when a Terminal session is opened) then ~/.bash_profile or ~/.profile will be executed, depending on which exists, which shell is being used, etc.

If further shells are opened from this login shell, in which to enter commands (i.e., interactive shells), then the profile script is not run. However, if a shell configuration file is available (for example ~/.bashrc for Bash) then that file is run. This is the file which by convention contains aliases and functions.

Finally, if a script is run then the shell that is created for the duration of that script will not cause any of these configuration scripts to run.

Bash checks for the environment variable ENV when running as /bin/sh, and if the variable is present the script referred to is executed.

A 'common' configuration therefore is to have settings and shell commands that are executed when creating interactive shells, in ~/.bashrc, and settings and shell commands that apply only to login shells, in ~/.bash_profile or ~/.profile. To avoid duplication the commands for interactive shells can be executed from the login scripts. To illustrate, a ~/.bash_profile file might look like this:

# Setup a reference to the configuration for interactive shells:
#
export BASH_ENV=~/.bashrc
export ENV=$BASH_ENV

# If the file referred to exists then run it:
#
if [ -f $BASH_ENV ]; then . $BASH_ENV; fi

and the related ~/.bashrc file might look like this:

ls ()
{
  ls -al $@
}

ShellCommand's Approach

Of the various possible permutations of shells, ShellCommand creates a non-interactive, non-login shell to run its commands. This avoids:

  • executing any profile scripts, which may contain a lot more functionality than is necessary for a small command;
  • creating an interactive shell, which does all sorts of additional things, such as checking for email.

However, this does mean that if we want any settings that are used in interactive shells we need to load them, since Bash won't do it for us. For this reason, just before the required command is run ShellCommand checks the environment variable ENV to locate any interactive shell script, and if the variable is present the script referred to is executed.

Note that when running Sublime on Mac OS via its icon, the ENV value is not propagated through. This is a 'feature' of Mac OS rather than Sublime, and there are two ways around this. The first is to use the launchctl command in profile scripts to make specific environment variables available to GUI applications:

# Setup a reference to the configuration for interactive shells:
#
export BASH_ENV=~/.bashrc
export ENV=$BASH_ENV
launchctl setenv BASH_ENV $BASH_ENV
launchctl setenv ENV $ENV

# If the file referred to exists then run it:
#
if [ -f $BASH_ENV ]; then . $BASH_ENV; fi

The second technique is to use the shell_configuration_file option in settings, which can refer to a script to execute before each command. For example:

{
  "shell_configuration_file": "~/.sublime_functions"
}

The ~/.sublime_functions script might contain:

st ()
{
  git status
}

Aliases versus Functions

For some reason aliases don't work within shells created in Python, but functions do. There are some suggestions that functions are preferred over aliases anyway, but regardless of whether that's true or not, any aliases that are needed within ShellCommand would have to be mapped to functions. So this:

alias ls=ls -al

would need to become this:

function ls ()
{
  ls -al $@
}

or this (since function is optional):

ls ()
{
  ls -al $@
}

Note that with aliases, anything on the command-line that appears after a matched alias will be passed through after the alias is switched in, but with functions we need to add $@ to pick up any remaining parameters.