Runtime Environment
— print (last updated: Jun 25, 2009) print

Select font size:
Personalize this document by entering your login into the form in order to replace the usage of the generic LOGIN whenever relevant.
   

Description

An application's runtime environment is usually considered to be the set of exported global variables. By convention, these variables are upper-case. To see a shell's environment, run either of the commands:
$ printenv
$ export
Perhaps the most important of these is the PATH variable, which specifies the directories in which an executable file can be found. You can see it's current value by doing:
$ printenv PATH
$ echo $PATH

Interactive Shell Environment

An interactive command shell also has access to other settings: Aliases can be seen by running:
$ alias
Environment variables, functions and shell settings can be seen by running the set command. The output of set is quite large, so you probably want to page through it:
$ set | more          (type "q" to stop paging)
Examples of settings which are not environment variables are:
PS1:       initial shell prompt
LS_COLORS: colorization codes used for file listing
SHELLOPTS: interactive shell options
COLUMNS:   number of columns in terminal (80)
One can contrast, say, PATH to PS1 by executing:
$ echo $PS1             (should print 80)
$ printenv PS1          (nothing)

File Editing/Creation

Try to remember the implications of my saying "create the file" or "edit the file." Here are the key ideas:
  1. choose an editor: nano, vim, gedit, kate. In some circumstances you must use nano or vim.
  2. Decide whether you need to be root (sudo). Usually a file name with the path name starting with "/", it is a system file and you need to be root. For example, the instructions below say:
    "create the file /etc/profile.d/local.sh"
    which might be achieved by this:
    $ sudo gedit /etc/profile.d/local.sh &
    
    If a file starts with "~", it means it resides in your home directory and you do not want to be root to edit it. For example, the instructions below say:
    "edit the file ~/.bashrc"
    which might be achieved by this:
    $ gedit ~/.bashrc &
    

Environment Configuration

Follow these steps to set up a suitable shell environment.

System-wide settings

  1. Create the file /etc/profile.d/local.sh for system-wide exported variable modifications/additions. Make sure there is no space around the = sign!. You can omit the comment lines (starting with "#").
    # add home-bin to front of PATH
    PATH=$HOME/bin:$PATH
    
    # add "." to the back of PATH
    # there are some security issues, so we'll avoid having it for root
    # if the user activating this script is root, "id -u" will equal "0"
    # MAKE SURE THE BRACKETS "[" and "]" DO NOT TOUCH THE INSIDE EXPRESSION
    [ $(id -u) -ne 0 ] && PATH=$PATH:.
    
    # optional: 
    # set default system-wide EDITOR to nano if you cannot deal with vim
    # this is useful for a number of administrative commands which 
    # invoke an editor automatically: sudoedit, visudo, edquota
    #EDITOR=nano
    
    
  2. Create the file /etc/bash_aliases for system-wide settings. Again, no space around the = sign, and comments can be omitted.
    # listing aliases
    alias ll='ls -la'
    alias la='ls -A'
    alias lld='ls -ld'
    alias l='ls -CF'
    
    # force querying for potentially destructive operations
    alias rm='rm -i'
    alias mv='mv -i'
    alias cp='cp -i'
    
    alias path='printenv PATH'
    alias more='less'     # less is a better (poorly named) pager than more
    
    # augments the SHELLOPTS setting with the "noclobber" option
    # so that output redirection to an existing file with ">" is 
    # prevented and must be overwritten with ">|"
    set -C
    
    

Personal settings for LOGIN

  1. Edit ~/.bashrc and look for the commented lines:
    #if [ -f ~/.bash_aliases ]; then
    #    . ~/.bash_aliases
    #fi
    
    Uncomment these 3 lines and add others above them, getting:
    if [ -f /etc/bash_aliases ]; then
        . /etc/bash_aliases
    fi
    
    if [ -f ~/.bash_aliases ]; then
        . ~/.bash_aliases
    fi
    
  2. Create the file ~/.bash_aliases of your personal aliases and add these settings:
    # start a root shell via the "best" method
    # feel free to choose a name other than besu
    alias besu='sudo -H bash -l'
    
    # this sets the title for the terminal bar correctly 
    # for the terminal shell application
    PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}\007"'
    
    # this is a convenience for editing "your" files with gedit, where
    # we want the invocation for the FIRST file, file1, to be:
    #   gedit file1 &
    # and the invocation of all other files to be:
    #   gedit file
    e() { 
      # the "ps" part prints users of all gedit processes; the "grep" part
      # selects sends "success" if there are any for me "id -un"
      if ps -C gedit -o user= | grep -q $(id -un); then
        # later gedit invocations
        gedit "$@"
      else
        # first gedit invocation
        gedit "$@" &
      fi
    }
    
    
  3. Edit ~/.profile and remove (or comment out) these three lines
    if [ -d "$HOME/bin" ] ; then
        PATH="$HOME/bin:$PATH"
    fi
    
    We acquire the home-bin portion of the PATH from the global environment.
  4. Create a directory for your personal executables:
    $ mkdir ~/bin
    
  5. Color Prompt
    Our TERM is xterm, which you can verify by typing:
    $ echo $TERM
    
    It clearly supports color, but the ~/.bashrc script doesn't turn color on automatically.

    Edit ~/.bashrc and look for these lines:
    # uncomment for a colored prompt, if the terminal has the capability; turned
    # off by default to not distract the user: the focus in a terminal window
    # should be on the output of commands, not on the prompt
    #force_color_prompt=yes
    
    As suggested, uncomment the last line:
    force_color_prompt=yes
    
    The actual color settings are done later in this block:
    if [ "$color_prompt" = yes ]; then
        PS1=...
    else
        PS1=...
    fi
    
    Color/style settings are created by the "special strings" like "\[\033[01;32m\]" which you see in the prompt definition. Some alternative color/styles you can try are these:
    \[\033[01;31m\]            (bold/red)
    \[\033[01;34m\]            (normal/reddish)
    
    Just make sure that the last color change string is "\[\033[00m\]".
  6. Optional Shortened Prompt
    The standard Bash prompt can be "overly long", leaving little space for the command when you get sufficiently deep into the directory structure.

    Edit ~/.bashrc and look for these lines:
    if [ "$color_prompt" = yes ]; then
        PS1='... \w\[\033[00m\]\$ '
    else
        PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
    fi
    
    Replacing the occurrences of "\w" by "\W" (lower case to upper case) will show only the basename of the current working directory. Another common alternative, similar to the Windows DOS shell prompt, is to make the prompt complete on the following line after the full directory is printed. Do this by inserting a newline character "\n" just before the end of the prompt string, i.e, make "\$" into "\n\$".
To pick up the environment changes, you need to log out and then log back in. Afterwards, open a new command shell and see some of the effects:
$ alias             -- you should see the aliases listed here

$ path
/home/LOGIN/bin:/usr/local/sbin:
/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:.

------------------ we want to observe the "e()" function:
$ set | more
type: /^e followed by Enter, replacing the ":"
type q to leave pager 

Settings for root

We want to do similar things for the root user.
  1. Edit /root/.bashrc
    Do the same thing as in the step 1 in the "personal settings" section above.
  2. Create a directory for root-only executables:
    $ sudo mkdir /root/bin
    
  3. Setting a color prompt is different in /root/.bashrc. The easiest way is to look for:
    case "$TERM" in
    xterm-color)
        PS1=...
        ;;
    *)
        PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
        ;;
    esac
    
    and change the case test to:
    xterm*)
    

Settings for other non-root users

New users obtain their startup files from the directory /etc/skel.
$ sudo cp ~/.bashrc ~/.profile /etc/skel
$ sudo mkdir /etc/skel/bin

Comparison of root shell operations

Open a shell.
$ path               Observe home-bin and . in PATH

$ sudo su
# path               no /root/bin in PATH
# pwd                working directory unchanged
# exit

$ sudo su -
# path               PATH has /root/bin
# pwd                working directory is /root
# exit

$ besu
# path               PATH has /root/bin
# pwd                working directory unchanged
# exit

Experiment with environment setup

A bash script something.sh can be executed or sourced. Executing a bash script is this:
$ bash something.sh
If the script is executable, you can omit the "bash" call. Unlike calling bash by itself, this is a non-interactive shell. When you want to use a script like a program, what you want is to execute it. The script is run in a subshell and has no effect on the environment of the current shell.

In contrast, sourcing executes the statements, but the purpose of sourcing a bash file is primarily to augment the environment. The exported variables are created by the shell command
export VARIABLE
Usually the export statement is combined with the variable's definition, like
export VARIABLE=value
which is equivalent to these two statements (in either order):
export VARIABLE
VARIABLE=value
Syntactically, sourcing the file something.sh is done in either of these two synonymous ways:
$ source something.sh
or
$ . something.sh
Here is an example. Use an editor to create these two simple scripts:

setVars.sh
AA='hello' export BB='world'

showVars.sh
echo 'AA=' $AA echo 'BB=' $BB
Try this sequence of commands:
$ bash setVars.sh     execution: variables AA, BB set in a subshell
$ echo $AA $BB        AA, BB undefined
$ . setVars.sh        source: variables set in current shell
$ echo $AA $BB        AA, BB now defined
$ . showVars.sh       source: both variables appear
$ bash showVars.sh    execution: only the exported one appears

Interactive settings not passed to execution

Like un-exported variables, aliases and functions are only available to the interactive shell, not to executed scripts. Suppose you have the path alias working in the shell, i.e.
$ path               (shows value of PATH)
Then, for example, suppose you define this one-line script named showPath.sh:
path
The execution will fail:
$ bash showPath.sh
whereas sourcing will succeed:
$ . showPath.sh

Discussion

The runtime environment is created initially through the login process. The login process is initiated in three common ways:
  1. local entry via a graphical login — for us this is controlled by the executable gdm.
  2. remote entry via secure shell.
  3. local entry via a terminal console (Ctrl-Alt-F1, ..., Ctrl-Alt-F6). Ctrl-Alt-F7 is the graphical console.
The login process assigns a shell (the login shell) to the user as specified in the file:
/etc/passwd
The login shell created obtains its initial environment from:
/etc/environment
and then augments the environment by sourcing these two files:
/etc/profile
~/.profile         (or ~/.bash_profile or ~/.bash_login supercede, if existing)
Other files contribute to the environment by being sourced explicitly in these two files. For Ubuntu, these additional sourcings are used:
/etc/profile    sources    /etc/profile.d/*.sh
/etc/profile    sources    /etc/bash.bashrc    if the shell is interactive
~/.profile      sources    ~/.bashrc           if the shell is interactive

Additions/modifications of runtime environment

It's considered good practice to avoid modifying the basic system files /etc/profile and /etc/bash.bashrc since these may be modified in updates to the bash package. Here is our logic for additions/modifications:
  1. Environment variables for all users (you and root at least) are entered into a .sh file in /etc/profile.d/, which for us is
    /etc/profile.d/local.sh
    You can add other .sh files or use this one only.
  2. Environment variables for only you are added to ~/.profile.
  3. Interactive shell settings (aliases, functions, other variables) for you only are entered into ~/.bashrc.
  4. Interactive shell settings for all users are entered into /etc/bash_aliases. The file /etc/bash.bashrc is sourced for each shell, but it is not a good idea to modify this, because it could be replace by future upgrades. Otherwise, Ubuntu provides no standard global file which is sourced by all users when a shell is invoked; thus we chose /etc/bash_aliases to be such a file and have decided to modify all relevant .bashrc files to source this one.


© Robert M. Kline