Shell Variables
Operating System vs. Shell
- Operating system (OS) manages your hardware
- Provides a set of system calls to make different machines look the same to user-level programs
- Command shell (or just "shell") is a text UI for interacting with the operating system
- And with user-level programs
- There are many different shells for Unix and Windows
- Bash and Zsh are compatible with the POSIX standard
- Fish is nicer, but is not
- Nushell is even stranger
- PowerShell on Windows (and Unix) has a lot of nice features too
- We use Bash in this tutorial but will discuss Nushell later
Shell Variables
- The shell is a program and programs have variables
- Create or change with
name=value - Shell variable stays in the process that created it
- E.g., that particular running copy of the shell
- Use
$nameto get value$prefix because people type file and directory names more often
WINDOW="neighbor"
echo "outer: window is ${WINDOW}"
bash src/shell_var_inner.sh
echo "inner: window is ${window}"
outer: window is neighbor
inner: window is
- Note: variables usually written in upper case to distinguish them from filenames
- So use underscores as separators
Exercise: Single Quotes
What happens if you modify the scripts shown above to use single quotes instead of double quotes?
Environment Variables
- Environment variable is inherited by new processes
- Use
export name=value
WINDOW="neighbor"
export THRESHOLD=0.5
echo "outer: window is ${WINDOW} and threshold is ${THRESHOLD}"
bash src/env_var_inner.sh
echo "inner: window is ${window} and threshold is ${threshold}"
outer: window is neighbor and threshold is 0.5
inner: window is and threshold is
Exercise: Setting in Children
If a child process sets shell or environment variables, are they visible in the parent once the child finishes executing?
Environment Variables in Programs
- Since environment variables are inherited by child processes, they are inherited by all programs run from the shell that has them
WINDOW="neighbor"
export THRESHOLD=0.5
echo "outer: window is ${WINDOW} and threshold is ${THRESHOLD}"
python src/env_var_py.py
import os
window = os.getenv("WINDOW", default="not set")
threshold = os.getenv("THRESHOLD", default="not set")
print(f"inner: window is {window} and threshold is {threshold}")
outer: window is neighbor and threshold is 0.5
inner: window is not set and threshold is 0.5
Inspecting Variables
seton its own lists variables- And functions, because yes, you can create those in the shell
- But please don't: if you need that, write a Python script
envshows all environment variables
env | cut -d = -f 1 | sort | head -n 10
BASH_SILENCE_DEPRECATION_WARNING
CONDA_DEFAULT_ENV
CONDA_EXE
CONDA_PREFIX
CONDA_PREFIX_1
CONDA_PROMPT_MODIFIER
CONDA_PYTHON_EXE
CONDA_SHLVL
EDITOR
GEM_HOME
- Many tools rely on variables to manage configuration
Exercise: Python vs. the Shell
The os.environ variable in Python's os module
is an easy way to get all of the process's environment variables.
Compare it to what env shows.
-
Are there differences?
-
If so, what are they and why do they exist?
Important Environment Variables
- 37 environment variables in my current shell
- Most important are shown in [%t var_common %]
| Name | Typical Value | Purpose |
|---|---|---|
EDITOR |
nano |
default text editor |
HOME |
/Users/tut |
user's home directory |
LANG |
en_CA.UTF-8 |
user's preferred (human) language |
PATH |
see below | search path for programs |
PWD |
/Users/tut/sys |
present working directory |
SHELL |
/bin/bash |
user's default shell |
TERM |
xterm-256color |
type of terminal |
TMPDIR |
/var/tmp |
storage for temporary files |
USER |
tut |
current user's name |
Search Path
PATHholds a colon-separated list of directories- Shell looks in these in order to find commands
- Reading at them all on one line is difficult, so use
trto split
echo $PATH | tr : '\n'
/Users/tut/google-cloud-sdk/bin
/Users/tut/conda/envs/sys/bin
/Users/tut/conda/condabin
/Users/tut/.nvm/versions/node/v20.8.0/bin
/Users/tut/bin
/Applications/Postgres.app/Contents/Versions/14/bin
/Users/tut/go/bin
/usr/local/bin
/System/Cryptexes/App/usr/bin
/usr/bin
/bin
/usr/sbin
/sbin
/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin
/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin
/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin
/Library/Apple/usr/bin
/Library/TeX/texbin
/usr/local/bin
- Notice
/Users/tut/bin - Common to have a
~/bindirectory with the user's own utilities
Adding to the Search Path
- Shell variables (of both kinds) are just strings
- So add to search path by redefining the variable
- New directory at the from
- Entire old value at the back
export PATH="/tmp/bin:${PATH}"
echo $PATH | tr : '\n' | head -n 5
/tmp/bin
/Users/gregwilson/google-cloud-sdk/bin
/Users/gregwilson/conda/envs/sys/bin
/Users/gregwilson/conda/condabin
/Users/gregwilson/.gem/ruby/3.1.2/bin
Exercise: Shortening the Path
Removing a directory from PATH is harder than adding one.
Write a shell script that:
- Splits
PATHon colons to put one entry on each line. - Uses
grepto remove the undesired line. - Uses
paste -s -d :to recombine the lines. - Uses command interpolation to assign the result back to
PATH.
This exercise may remind you why complicated operations should be done in Python rather than in the shell.
Startup Files
- Bash shell runs commands in
~/.bash_profilefor login shells - Bash shell runs commands in
~/.bashrcfor interactive shells - Yes, the terminology is confusing
- Common to have
~/.bash_profile[%g source_shell "source" %]~/.bashrc- I.e., run those commands in the current shell
source $HOME/.bashrc
Command Interpolation
- Can use
outer $(inner)to runinnerand use its output as arguments toouter - Long-winded way to count lines in some text files
wc -l $(ls src/*.text)
12 src/ctrl_z_background.text
12 src/kill_int.text
6 src/kill_process.text
30 total