1. Overview
Each Linux process has its own set of environment variables, which it inherits from its parent. For example, when we execute a command in our shell, the command inherits the environment variables of the shell.
In this tutorial, we’ll take a look at how we can manage the environment variables using env, printenv, and export.
Although we’ll be using Bash, all examples in this article should also work in POSIX-compatible shells.
2. Global Environment Variables
When we start a shell, it’s created with a set of predefined environment variables. We can declare them globally or on a per-user basis.
With Bash, we can declare global variables in, e.g., /etc/profile. However, it’s usually better to declare them in separate script files and to include those in the /etc/profile.d file. Bash should then automatically pick these up.
Global variables affect all users in the system. Each user can create a set of personal environment variables by creating ~/.profile in their home directory and declaring them there.
One of the most common environment variables we use daily is the PATH variable. PATH contains a list of locations for our shell to search for executables. We can add something to our PATH by creating a ~/.profile containing similar information:
PATH=$PATH:/path/to/executable/
Here, we redeclare the PATH variable, set its value to the current value of PATH, and add /path/to/executable/ to it.
In the next sections, we describe the commands most commonly used to manage environment variables. Let’s start with env and printenv.
3. env and printenv
We’ve already mentioned that each process runs in its own environment. We can use env to run a program in a modified environment, by supplying additional environment variables:
$ env CUSTOM_VAR=42 /path/to/script.sh
In this example, env executes /path/to/script.sh in an environment that’s a copy of our shell environment with CUSTOM_VAR as an added environment variable with value 42.
Additionally, env can accept a list of space-separated variables. Therefore, we can add multiple variables:
$ env VAR_ONE=1 VAR_TWO=2 /path/to/script.sh
We can also unset or remove variables by preceding them with -u:
$ env -u PATH /path/to/script.sh
This will run our script in a copy of the current environment but without the PATH variable.
We can even run our script in an empty environment:
$ env -i /path/to/scripts.sh
The -i option, shorthand for –ignore-environment, runs the given commands with an empty environment.
Finally, running env without arguments will print a list of all variables in the current environment.
We can accomplish the same with printenv:
$ printenv
HOSTNAME=localhost.localdomain
TERM=xterm-256color
SHELL=/bin/bash
HISTSIZE=1000SSH_TTY=/dev/pts/0
USER=vagrant
MAIL=/var/spool/mail/vagrant
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin
PWD=/home/vagrant
LANG=en_US.UTF-8
HOME=/home/vagrant
LOGNAME=vagrant
We can also print values of particular variables by providing a space-separated list of variable names:
$ printenv HOSTNAME PATH HOME
localhost.localdomain
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin
/home/vagrant
This operation prints the value of each provided variable name in a new line.
4. export
We should not confuse environment variables with shell variables. Shell variables are those that apply to our current shell only and aren’t inherited by any programs or scripts that we execute.
We can get an overview of all variables that apply to the current shell by calling set:
$ set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
HOSTNAME=localhost.localdomain
TERM=xterm-256color
SHELL=/bin/bash
HISTSIZE=1000SSH_TTY=/dev/pts/0
USER=vagrant
MAIL=/var/spool/mail/vagrant
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin
PWD=/home/vagrant
LANG=en_US.UTF-8 HOME=/home/vagrant
LOGNAME=vagrant
We can see shell variables specific to Bash and all environment variables we printed before using printenv.
Subprocesses don’t inherit shell variables, but we can export them to make them visible. We can best explain this by an example.
First, let’s create a new shell variable:
$ CUSTOM_VAR=42
We can print the value of our variable with echo:
$ echo "Custom var value: $CUSTOM_VAR"
42
To verify that the variable can’t be seen from a subprocess, let’s put the echo command in a script that we’ll name print_custom_var.sh:
$ cat ./print_custom_var.sh
#!/bin/bash
echo "Custom var value: $CUSTOM_VAR"
When we run the script the output will be:
$ ./print_custom_var.sh
Custom var value:
Our script can’t see the value of CUSTOM_VAR, because the CUSTOM_VAR doesn’t exist for the script.
We can make it visible to subprocesses with the export command:
$ export CUSTOM_VAR
Now, let’s run the script again:
$ ./print_custom_var.sh
Custom var value: 42
Thus, the export command can make the value of any variable visible to subprocesses.
5. Conclusion
In this article, we learned how to manage environment variables.
First, we learned how to set global environment variables using locations like /etc/profile.d and ~/.profile. Then, we saw different ways to manage environment variables using env, printenv, and export.