10 Environment
- Distinguish between local shell variables and environment variables and explain how
exportchanges inheritance. - Use
PATHandwhichto locate commands and add custom script directories. - Create and persist aliases and configuration changes in shell startup files.
10.1 Environment variables
In the arguments and variables chapter, we introduced environment variables: variables that the shell loads automatically when it starts. System or user configuration files define these variables, and they can affect how the operating system behaves. For example, programs may use environment variables to find files or directories that they need.
Use printenv to display the variables defined in your current environment:
printenvHere are some common environment variables:
$HOMEstores your home directory.$USERstores your username.$SHELLindicates which interpreter the current shell uses. This is usually/bin/bash, but/bin/zshis also common, especially on macOS.$PATHstores a list of directories where the shell looks for executable programs. We will discuss this variable in detail below.$PWDstores your current working directory. This dynamic variable changes each time you change directory.
Use the echo command to access the value of an environment variable, just as you would access any other shell variable. For example:
echo "Hello $USER!"
echo "Your home directory is located in: $HOME"
echo "Currently you're located in: $PWD"10.1.1 Local vs global variables
A shell variable is local to the shell by default. Child processes, such as a shell script that you run from the terminal, cannot access local variables unless you export them.
For example, define the following variable in your shell:
hello_message="Hello $USER!"You can use the variable in the current shell:
echo $hello_messageHello participant!
However, if you include the same variable in a shell script (for example, print_hello.sh):
#!/usr/bin/env bash
echo "Greeting message:"
echo $hello_messageThen execute the script from the terminal:
bash print_hello.shGreeting message:
The script prints an empty value because hello_message is a local variable in the active shell. The script runs in a child process, which does not inherit local variables.
Use the export command to make a variable available to child processes:
export hello_message="Hello $USER!"Run the script again:
bash print_hello.shGreeting message:
Hello participant!
The exported variable also appears in the output from printenv.
Exporting a variable makes it available to child processes, but it does not make the variable permanent. If you close your terminal and start a new session, the variable will no longer be available.
To load variables automatically in future sessions, add their definitions to a configuration file such as .bashrc/.zshrc, which we discuss below.
10.2 Finding software with PATH
When you type a command, the shell uses the PATH variable to find the corresponding executable program. For example, when you type ls, cat, or grep, the shell searches a set of predefined directories.
Use the which command to see which executable the shell finds for a program:
which grep/usr/bin/grep
The PATH variable includes /usr/bin, so the shell can find grep there:
echo $PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin
Your PATH will probably differ from this example. Each directory appears in a colon-separated list. When you type a command, the shell searches these directories in order and runs the first matching executable. If the shell finds no match, it throws and error: command not found.
10.2.1 Adding a custom directory to PATH
You can add directories to PATH when you want to run personal scripts or locally installed software as regular commands.
The my_programs directory contains three example scripts:
cd ~/Desktop/data-shell
ls my_programscountfiles cow sysinfo
These files have no extension, but they are shell scripts. You can edit them with nano or display their contents with cat. Run one of the scripts with bash:
bash my_programs/countfilesFiles in /home/participant/Desktop/data-shell/:
2
This script counts the regular files (i.e. it excludes directories) in the current directory.
To run these scripts as regular commands, first give the user execute permission. Without execute permission, you must run each script through the bash program. Use the chmod command we learned about in the permissions chapter:
chmod u+x my_programs/*
ls -l my_programs-rwxrw-r-- 1 participant participant 80 Aug 25 11:38 countfiles
-rwxrw-r-- 1 participant participant 219 Aug 25 11:37 cow
-rwxrw-r-- 1 participant participant 158 Aug 25 11:37 sysinfo
The first three permission characters after the file type are now rwx, so the user can read, write, and execute these files. When you run an executable script, the #! shebang at the start of the file tells the operating system which interpreter to use. In this example, the scripts use bash.
Add the directory containing these scripts to the front of PATH:
PATH="$HOME/Desktop/data-shell/my_programs/:$PATH"This assignment combines the new directory with the existing value of PATH:
PATH=assigns a new value to the variable.$HOME/Desktop/data-shell/my_programs/is the directory to add. Using$HOMEmakes the path relative to your home directory.:separates directories in thePATHlist.$PATHpreserves the directories that were already inPATH. Placing the new directory first means the shell searches it before the existing directories.
Print PATH to confirm that the new directory appears at the front:
echo $PATH/home/participant/Desktop/data-shell/my_programs:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
You can now run any of the scripts by typing its name:
sysinfoUser: participant
Hostname: training-pc
Kernel: Linux
Machine: x86_64
Uptime: up 2 hours, 17 minutes
The #! shebang from the shell scripts chapter specifies which program should execute a script. We used #!/usr/bin/env bash for the shell scripts in this chapter, but a shebang can specify another interpreter, such as:
#!/usr/bin/env python3uses Python to execute the script.#!/usr/bin/env Rscriptuses R to execute the script.
Any interpreter that can execute scripts can appear in a shebang.
10.3 Aliases
Adding a directory to PATH makes its scripts available as regular commands. An alias provides another way to simplify commands by assigning a short name to a command and its options.
For example, you might often use these ls options:
-llists files in long format.-hdisplays file sizes in a human-readable format.-Ssorts files by size.--color=alwaysalways uses colours in the output.
Typing ls -l -h -S --color=always each time is repetitive. Let’s create an alias named lss (for “ls sorted by size) for this command:
alias lss="ls -l -h -S --color=always"You can now type lss to list the contents of molecules with these options:
lss molecules-rwxr--r-- 1 participant participant 1.8K Jun 6 2025 octane.pdb
-rwxr--r-- 1 participant participant 1.2K Jun 6 2025 pentane.pdb
-rwxr--r-- 1 participant participant 1.2K Jun 6 2025 cubane.pdb
-rwxr--r-- 1 participant participant 825 Jun 6 2025 propane.pdb
-rwxr--r-- 1 participant participant 622 Jun 6 2025 ethane.pdb
-rwxr--r-- 1 participant participant 422 Jun 6 2025 methane.pdb
10.4 Configuration files
The variable, PATH, and alias changes in the previous sections affect only the active shell. When you close the terminal and start a new session, the shell returns to its default environment.
Configuration files let you load changes whenever you start a new shell. The shell itself is a program, and different shells have different configuration files and behaviours. You can check which shell you’re using with:
echo $SHELLFor most Linux users their default shell is bash, but for macOS users it is zsh. Depending on which of these two you have, the most common configuration files are:
.bashrcfor abashshell.zshrcfor azshshell
For your convenience, select your shell so the text below shows you the right configuration file:
All this does is use either .bashrc or .zshrc in the text that follows. But the explanations are identical otherwise.
You can inspect the contents of your configuration file with:
cat ~/__QUARTO_SHELL_FILE__The contents of __QUARTO_SHELL_FILE__ vary between operating systems and users. Some programs also modify this file during installation, for example by adding their executable directories to PATH.
The shell treats __QUARTO_SHELL_FILE__ as a script, so you can place valid Bash commands in it. Before editing the file, create a backup so that you can restore the original if necessary:
cp ~/__QUARTO_SHELL_FILE__ ~/__QUARTO_SHELL_FILE___unix_course_bkpBack up __QUARTO_SHELL_FILE__ before you edit it. This configuration file may contain settings that your environment needs, and an incorrect change can prevent commands or other configuration from working.
You can safely experiment if you keep the backup and restore it when necessary.
Open the file with a text editor. This example uses nano, but you can use any text editor:
nano ~/__QUARTO_SHELL_FILE__Add your own changes at the bottom of the file and leave the existing configuration unchanged. A comment can identify the lines that you added. For example, add a welcome message that prints each time you start a session:
# User edit: add a welcome message
echo "Hello $USER - welcome back!"Save __QUARTO_SHELL_FILE__, then start a new terminal. The new shell reads __QUARTO_SHELL_FILE__ and executes its commands, so it prints the welcome message.
You can use the same file to define persistent environment variables, update PATH, and create aliases. The exercises below let you practise these changes.
ls hides files and directories whose names start with . by default. Use ls -a to list all files, including hidden files.
Configuration files and directories often start with . to keep them out of the usual filesystem listing.
10.5 Exercises
Before starting these exercises, check which shell you’re using with:
echo $SHELLAnd make your selection accordingly:
Before you edit __QUARTO_SHELL_FILE__, create a backup so that you can undo an accidental change that disrupts your environment.
10.6 Summary
- Local variables stay in the current shell, while environment variables are inherited by child processes.
exportmakes a variable available to scripts and commands started from the shell.printenvlists the current environment, andecho $VARdisplays a variable value.
PATHtells the shell where to find executable programs.whichshows the program the shell will run.- Adding a directory to
PATHlets you run custom scripts as commands. - A shebang tells the operating system which interpreter should execute a script.
- Aliases and shell configuration files make commands easier to use repeatedly.
aliascreates a shortcut for a longer command..bashrcor.zshrcloads custom settings when a new shell starts.- Persistent changes help you keep favourite commands, variables, and script paths available.