Report this

What is the reason for this report?

How To Read and Set Environmental and Shell Variables on Linux

Updated on January 2, 2026
English
How To Read and Set Environmental and Shell Variables on Linux

Introduction

When interacting with your server through a shell session, there are many pieces of information that your shell compiles to determine its behavior and access to resources. Some of these settings are contained within configuration settings and others are determined by user input.

One way that the shell keeps track of all of these settings and details is through an area it maintains called the environment. The environment is an area that the shell builds every time that it starts a session that contains variables that define system properties.

In this guide, we will discuss how to interact with the environment and read or set environmental and shell variables interactively and through configuration files.

Note: This tutorial has been validated on the latest Linux distributions including Ubuntu 22.04 LTS, Ubuntu 24.04 LTS, Debian 12, CentOS Stream 9, and Rocky Linux 9. All commands and examples work on modern Linux systems with Bash 5.x and later versions.

If you’d like to follow along using your local system or a remote server, open a terminal and run the commands from this tutorial there.

Key Takeaways

Before diving into the details, here are the essential points about environment and shell variables on Linux:

  • Environment variables are inherited by child processes and affect system-wide behavior, while shell variables are local to the current shell session
  • Use printenv or env to view environment variables, and set to see all shell and environment variables
  • The export command converts shell variables to environment variables, making them available to child processes
  • To make variables persistent across sessions, add them to shell configuration files like ~/.bashrc or ~/.profile
  • Understanding variable scope and inheritance is crucial for proper configuration management and security

How the Environment and Environmental Variables Work

Every time a shell session spawns, a process takes place to gather and compile information that should be available to the shell process and its child processes. It obtains the data for these settings from a variety of different files and settings on the system.

The environment provides a medium through which the shell process can get or set settings and, in turn, pass these on to its child processes.

The environment is implemented as strings that represent key-value pairs. If multiple values are passed, they are typically separated by colon (:) characters. Each pair will generally look something like this:

KEY=value1:value2:...

If the value contains significant white-space, quotations are used:

KEY="value with spaces"

The keys in these scenarios are variables. They can be one of two types, environmental variables or shell variables.

Environmental variables are variables that are defined for the current shell and are inherited by any child shells or processes. Environmental variables are used to pass information into processes that are spawned from the shell. This inheritance mechanism is fundamental to how Linux processes communicate configuration information.

Shell variables are variables that are contained exclusively within the shell in which they were set or defined. They are often used to keep track of ephemeral data, like the current working directory. Unlike environment variables, shell variables are not automatically passed to child processes unless explicitly exported.

For more information about how Bash handles variables and scripting, see our tutorial on What is Bash?.

By convention, these types of variables are usually defined using all capital letters. This helps users distinguish environmental variables within other contexts.

Printing Shell and Environmental Variables

Each shell session keeps track of its own shell and environmental variables. We can access these in a few different ways.

We can see a list of all of our environmental variables by using the env or printenv commands. In their default state, they should function exactly the same:

  1. printenv

Your shell environment may have more or fewer variables set, with different values than the following output:

Output
SHELL
=/bin/bash TERM=xterm USER=demouser LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca:... MAIL=/var/mail/demouser PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games PWD=/home/demouser LANG=en_US.UTF-8 SHLVL=1 HOME=/home/demouser LOGNAME=demouser LESSOPEN=| /usr/bin/lesspipe %s LESSCLOSE=/usr/bin/lesspipe %s %s _=/usr/bin/printenv

This is fairly typical of the output of both printenv and env. The difference between the two commands is only apparent in their more specific functionality. For instance, with printenv, you can request the values of individual variables:

  1. printenv PATH
Output
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

On the other hand, env lets you modify the environment that programs run in by passing a set of variable definitions into a command like this:

  1. env VAR1="value" command_to_run command_options

Since, as we learned above, child processes typically inherit the environmental variables of the parent process, this gives you the opportunity to override values or add additional variables for the child.

As you can see from the output of our printenv command, there are quite a few environmental variables set up through our system files and processes without our input.

These show the environmental variables, but how do we see shell variables?

The set command can be used for this. If we type set without any additional parameters, we will get a list of all shell variables, environmental variables, local variables, and shell functions:

  1. set
Output
BASH
=/bin/bash BASHOPTS=checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath BASH_ALIASES=() BASH_ARGC=() BASH_ARGV=() BASH_CMDS=() . . .

This is usually a huge list. You probably want to pipe it into a pager program to more easily deal with the amount of output:

  1. set | less

The amount of additional information that we receive back is a bit overwhelming. We probably do not need to know all of the bash functions that are defined, for instance.

We can clean up the output by specifying that set should operate in POSIX mode, which won’t print the shell functions. We can execute this in a sub-shell so that it does not change our current environment:

  1. (set -o posix; set)

This will list all of the environmental and shell variables that are defined.

We can attempt to compare this output with the output of the env or printenv commands to try to get a list of only shell variables, but this will be imperfect due to the different ways that these commands output information:

  1. comm -23 <(set -o posix; set | sort) <(env | sort)

This will likely still include a few environmental variables, due to the fact that the set command outputs quoted values, while the printenv and env commands do not quote the values of strings.

This should still give you a good idea of the environmental and shell variables that are set in your session.

These variables are used for all sorts of things. They provide an alternative way of setting persistent values for the session between processes, without writing changes to a file.

Common Environmental and Shell Variables

Some environmental and shell variables are very useful and are referenced fairly often. The following table lists the most commonly used variables you’ll encounter:

Variable Type Description
SHELL Environment The shell that will be interpreting commands you type. Typically bash by default, but other values can be set if you prefer other options.
TERM Environment The type of terminal to emulate when running the shell. Different hardware terminals can be emulated for different operating requirements.
USER Environment The current logged in user.
PWD Environment The current working directory.
OLDPWD Environment The previous working directory. Kept by the shell to switch back to your previous directory by running cd -.
LS_COLORS Environment Color codes used to add colored output to the ls command. Helps distinguish different file types at a glance.
MAIL Environment The path to the current user’s mailbox.
PATH Environment A colon-separated list of directories that the system checks when looking for commands. Directories are searched in order when a user types a command.
LANG Environment The current language and localization settings, including character encoding.
HOME Environment The current user’s home directory.
_ Environment The most recent previously executed command.
BASHOPTS Shell The list of options that were used when bash was executed. Useful for determining if the shell environment will operate as expected.
BASH_VERSION Shell The version of bash being executed, in human-readable form.
BASH_VERSINFO Shell The version of bash, in machine-readable output format.
COLUMNS Shell The number of columns wide used to draw output on the screen.
DIRSTACK Shell The stack of directories available with the pushd and popd commands.
HISTFILESIZE Shell Number of lines of command history stored to a file.
HISTSIZE Shell Number of lines of command history allowed in memory.
HOSTNAME Shell The hostname of the computer at this time.
IFS Shell The internal field separator used to separate input on the command line. By default, this is a space.
PS1 Shell The primary command prompt definition. Defines what your prompt looks like when you start a shell session. PS2 is used for secondary prompts when a command spans multiple lines.
SHELLOPTS Shell Shell options that can be set with the set option.
UID Shell The UID (user identifier) of the current user.

Setting Shell and Environmental Variables

To better understand the difference between shell and environmental variables, and to introduce the syntax for setting these variables, we will do a small demonstration.

Creating Shell Variables

We will begin by defining a shell variable within our current session. This is easy to accomplish; we only need to specify a name and a value. We’ll adhere to the convention of keeping all caps for the variable name, and set it to a simple string.

  1. TEST_VAR='Hello World!'

Here, we’ve used quotations since the value of our variable contains a space. Furthermore, we’ve used single quotes because the exclamation point is a special character in the bash shell that normally expands to the bash history if it is not escaped or put into single quotes.

We now have a shell variable. This variable is available in our current session, but will not be passed down to child processes.

We can see this by grepping for our new variable within the set output:

  1. set | grep TEST_VAR
Output
TEST_VAR
='Hello World!'

We can verify that this is not an environmental variable by trying the same thing with printenv:

  1. printenv | grep TEST_VAR

No output should be returned.

Let’s take this as an opportunity to demonstrate a way of accessing the value of any shell or environmental variable.

  1. echo $TEST_VAR
Output
Hello World!

As you can see, reference the value of a variable by preceding it with a $ sign. The shell takes this to mean that it should substitute the value of the variable when it comes across this.

So now we have a shell variable. It shouldn’t be passed on to any child processes. We can spawn a new bash shell from within our current one to demonstrate:

  1. bash
  2. echo $TEST_VAR

If we type bash to spawn a child shell, and then try to access the contents of the variable, nothing will be returned. This is what we expected.

Get back to our original shell by typing exit:

  1. exit

Creating Environmental Variables

Now, let’s turn our shell variable into an environmental variable. We can do this by exporting the variable. The command to do so is appropriately named:

  1. export TEST_VAR

This will change our variable into an environmental variable. We can check this by checking our environmental listing again:

  1. printenv | grep TEST_VAR
Output
TEST_VAR
=Hello World!

This time, our variable shows up. Let’s try our experiment with our child shell again:

  1. bash
  2. echo $TEST_VAR
Output
Hello World!

Great! Our child shell has received the variable set by its parent. Before we exit this child shell, let’s try to export another variable. We can set environmental variables in a single step like this:

  1. export NEW_VAR="Testing export"

Test that it’s exported as an environmental variable:

  1. printenv | grep NEW_VAR
Output
NEW_VAR
=Testing export

Now, let’s exit back into our original shell:

  1. exit

Let’s see if our new variable is available:

  1. echo $NEW_VAR

Nothing is returned.

This is because environmental variables are only passed to child processes. There isn’t a built-in way of setting environmental variables of the parent shell. This is good in most cases and prevents programs from affecting the operating environment from which they were called.

The NEW_VAR variable was set as an environmental variable in our child shell. This variable would be available to itself and any of its child shells and processes. When we exited back into our main shell, that environment was destroyed.

Demoting and Unsetting Variables

We still have our TEST_VAR variable defined as an environmental variable. We can change it back into a shell variable by typing:

  1. export -n TEST_VAR

It is no longer an environmental variable:

  1. printenv | grep TEST_VAR

However, it is still a shell variable:

  1. set | grep TEST_VAR
Output
TEST_VAR
='Hello World!'

If we want to completely unset a variable, either shell or environmental, we can do so with the unset command:

  1. unset TEST_VAR

We can verify that it is no longer set:

  1. echo $TEST_VAR

Nothing is returned because the variable has been unset.

Setting Environmental Variables at Login

We’ve already mentioned that many programs use environmental variables to decide the specifics of how to operate. We do not want to have to set important variables up every time we start a new shell session, and we have already seen how many variables are already set upon login, so how do we make and define variables automatically?

This is actually a more complex problem than it initially seems, due to the numerous configuration files that the bash shell reads depending on how it is started.

The Difference between Login, Non-Login, Interactive, and Non-Interactive Shell Sessions

The bash shell reads different configuration files depending on how the session is started.

One distinction between different sessions is whether the shell is being spawned as a login or non-login session.

A login shell is a shell session that begins by authenticating the user. If you are signing into a terminal session or through SSH and authenticate, your shell session will be set as a login shell.

If you start a new shell session from within your authenticated session, like we did by calling the bash command from the terminal, a non-login shell session is started. You were not asked for your authentication details when you started your child shell.

Another distinction that can be made is whether a shell session is interactive, or non-interactive.

An interactive shell session is a shell session that is attached to a terminal. A non-interactive shell session is one is not attached to a terminal session.

So each shell session is classified as either login or non-login and interactive or non-interactive.

A normal session that begins with SSH is usually an interactive login shell. A script run from the command line is usually run in a non-interactive, non-login shell. A terminal session can be any combination of these two properties.

Whether a shell session is classified as a login or non-login shell has implications on which files are read to initialize the shell session.

A session started as a login session will read configuration details from the /etc/profile file first. It will then look for the first login shell configuration file in the user’s home directory to get user-specific configuration details.

It reads the first file that it can find out of ~/.bash_profile, ~/.bash_login, and ~/.profile and does not read any further files.

In contrast, a session defined as a non-login shell will read /etc/bash.bashrc and then the user-specific ~/.bashrc file to build its environment.

Non-interactive shells read the environmental variable called BASH_ENV and read the file specified to define the new environment. This is typically set to ~/.bashrc.

Implementing Environmental Variables

As you can see, there are a variety of different files that we would usually need to look at for placing our settings.

This provides a lot of flexibility that can help in specific situations where we want certain settings in a login shell, and other settings in a non-login shell. However, most of the time we will want the same settings in both situations.

Fortunately, most Linux distributions configure the login configuration files to source the non-login configuration files. This means that you can define environmental variables that you want in both inside the non-login configuration files. They will then be read in both scenarios.

We will usually be setting user-specific environmental variables, and we usually will want our settings to be available in both login and non-login shells. This means that the place to define these variables is in the ~/.bashrc file.

Open this file now:

  1. nano ~/.bashrc

This will most likely contain quite a bit of data already. Most of the definitions here are for setting bash options, which are unrelated to environmental variables. You can set environmental variables just like you would from the command line:

  1. export VARNAME=value

Any new environmental variables can be added anywhere in the ~/.bashrc file, as long as they aren’t placed in the middle of another command or for loop. We can then save and close the file. The next time you start a shell session, your environmental variable declaration will be read and passed on to the shell environment. You can force your current session to read the file now by typing:

  1. source ~/.bashrc

If you need to set system-wide variables, you may want to think about adding them to /etc/profile, /etc/bash.bashrc, or /etc/environment. System-wide variables affect all users on the system, so use caution when modifying these files.

Security Considerations for Environment Variables

Environment variables can contain sensitive information like API keys, database passwords, and authentication tokens. Understanding security implications is crucial for protecting your system and applications.

Security Best Practices

  • Never store sensitive data in plain text in configuration files that are committed to version control
  • Use appropriate file permissions for configuration files containing environment variables (typically 600 for user-specific files)
  • Avoid exporting sensitive variables unless absolutely necessary
  • Use secure methods for passing credentials, such as credential managers or encrypted configuration files
  • Be cautious with system-wide variables in /etc/environment or /etc/profile, as they’re visible to all users

Checking File Permissions

You can verify file permissions using the ls command with the -l flag:

  1. ls -l ~/.bashrc
Output
-rw-r--r-- 1 demouser demouser 3523 Dec 15 10:30 /home/demouser/.bashrc

To set more restrictive permissions on your .bashrc file:

  1. chmod 600 ~/.bashrc

This ensures only you can read and write the file.

Variable Scope and Security

Understanding variable scope helps prevent accidental exposure of sensitive data. Shell variables are safer for temporary sensitive data because they’re not automatically inherited by child processes. Only export variables when child processes need access to them.

Troubleshooting Common Issues

When working with environment and shell variables, you may encounter several common issues. Here are solutions to the most frequent problems:

Variable Not Available in Scripts

If an environment variable isn’t available in a script, check the following:

  1. Verify the variable is exported: Use printenv VARIABLE_NAME to confirm it’s an environment variable, not just a shell variable.
  2. Check script execution context: Scripts run in non-interactive shells may not source ~/.bashrc. Consider sourcing the configuration file explicitly or using ~/.profile for login shells.
  3. Verify variable name: Variable names are case-sensitive. MY_VAR and my_var are different variables.

Variable Not Persisting Across Sessions

If variables disappear after closing the terminal:

  1. Confirm the correct configuration file: Login shells read ~/.bash_profile or ~/.profile, while non-login shells read ~/.bashrc
  2. Check for syntax errors: Use bash -n ~/.bashrc to check for syntax errors
  3. Verify the file is sourced: Ensure your login shell configuration sources ~/.bashrc if needed

PATH Variable Issues

If commands aren’t found after adding directories to PATH:

  1. Check PATH order: Directories are searched in order. Ensure your directory is in the correct position
  2. Verify directory exists: Use ls to confirm the directory path is correct
  3. Check for typos: PATH entries are colon-separated. Ensure there are no extra spaces or missing colons

Conflicting Variable Definitions

If a variable behaves unexpectedly:

  1. Check all configuration files: Variables can be defined in multiple files (~/.bashrc, ~/.profile, /etc/profile)
  2. Use grep to find definitions: grep -r "VARIABLE_NAME" ~/.bash* /etc/profile
  3. Understand load order: Later definitions override earlier ones based on file load order

FAQs

1. What is the difference between env and export?

The env command is used to run a program in a modified environment or to display environment variables. When used with variable assignments, it sets variables only for that specific command execution:

  1. env VAR1="value" command_to_run

The export command, on the other hand, converts a shell variable into an environment variable, making it available to the current shell and all child processes:

  1. export VAR1="value"

The key difference is that export makes the variable persistent in your shell session, while env sets it only for a single command execution.

2. Why is my environment variable not available in scripts?

Environment variables may not be available in scripts for several reasons:

  1. Scripts run in non-interactive shells: Non-interactive shells don’t source ~/.bashrc by default. They may only read ~/.profile for login shells
  2. Variable not exported: If you set a variable without export, it’s a shell variable and won’t be inherited by child processes
  3. Script uses a different shell: If your script specifies a different shell (like #!/bin/sh), it may not read Bash-specific configuration files

To ensure variables are available in scripts, either export them in ~/.profile (for login shells) or explicitly source your configuration file in the script.

3. How do I set environment variables for all users?

To set environment variables for all users on the system, you have a few options:

  1. /etc/environment: Add variables in KEY=value format (no export needed). This file is read by PAM and affects all users
  2. /etc/profile: Add export VARIABLE=value lines. This affects all users for login shells
  3. /etc/bash.bashrc: Add export statements for all users in non-login Bash shells

Important: Always use sudo when editing system-wide files, and be cautious as changes affect all users. Test changes in your user-specific files first.

4. Are environment variables secure?

Environment variables can pose security risks if not managed properly:

  • Visibility: Environment variables are visible to all child processes and can be inspected using ps -e or /proc/[pid]/environ
  • Logging: They may be logged in shell history files or process logs
  • File permissions: Configuration files containing sensitive variables should have restrictive permissions (600)
  • Best practice: Never store passwords or API keys in environment variables committed to version control. Use secure credential management systems instead

For sensitive data, consider using encrypted configuration files, credential managers, or secure key storage systems rather than plain environment variables.

5. How do I unset an environment variable permanently?

To remove an environment variable permanently, you need to:

  1. Remove it from configuration files: Edit ~/.bashrc, ~/.profile, or system-wide files and delete or comment out the export statement
  2. Unset it in current session: Use unset VARIABLE_NAME to remove it from your current session
  3. Source the file: After editing, run source ~/.bashrc (or the appropriate file) to apply changes immediately

If the variable was set system-wide, you’ll need to edit the appropriate system file with sudo and restart your session for changes to take effect.

Conclusion

Environmental and shell variables are always present in your shell sessions and can be very useful. They provide a way for a parent process to set configuration details for its children, and offer a method of setting options outside of files.

This has many advantages in specific situations. For instance, some deployment mechanisms rely on environmental variables to configure authentication information. This is useful because it does not require keeping these in files that may be seen by outside parties.

There are plenty of other common scenarios where you will need to read or alter the environment of your system. These tools and techniques should give you a good foundation for making these changes and using them correctly.

Understanding variable scope, inheritance, and security implications helps you configure your Linux system effectively while maintaining good security practices.

Next Steps

Now that you understand how to work with environment and shell variables, you can apply this knowledge to more advanced shell scripting tasks. Consider exploring these related tutorials:

To practice working with environment variables in a real Linux environment, deploy a DigitalOcean Droplet and experiment with setting variables for your applications and scripts. DigitalOcean Droplets provide a clean Linux environment where you can safely test configuration changes without affecting your local system.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Justin Ellingwood
Justin Ellingwood
Author
See author profile

Former Senior Technical Writer at DigitalOcean, specializing in DevOps topics across multiple Linux distributions, including Ubuntu 18.04, 20.04, 22.04, as well as Debian 10 and 11.

Anish Singh Walia
Anish Singh Walia
Editor
Sr Technical Writer
See author profile

I help Businesses scale with AI x SEO x (authentic) Content that revives traffic and keeps leads flowing | 3,000,000+ Average monthly readers on Medium | Sr Technical Writer @ DigitalOcean | Ex-Cloud Consultant @ AMEX | Ex-Site Reliability Engineer(DevOps)@Nutanix

Category:

Still looking for an answer?

Was this helpful?


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Hi,

I think you addressed this in the beginning of the tutorial, but is it possible to set a shell/environment variable with two different arguments? For instance, I have an executable named “st” and another named “st_mona” and I want to set an environment variable inside the Makefile to both. The code right now is:

ST_BIN = st st_mona

But (if I read your article correctly) it seems to me that if this is possible it should instead read:

ST_BIN = st:st_mona

Is this right or entirely not possible?

@sgarrett: It’s important to remember that Makefiles are not actually shell scripts. There share a number of things, but Make is it’s own beast. The way you’re doing it is correct for make. You can check out the documentation for Make here:

http://www.gnu.org/software/make/manual/html_node/

Though it’s a bit overwhelming. Personally I always learn better by example. I’d suggest browsing around GitHub and looking at other project’s Makefiles.

Ah, thank you so much! That really helps :)

Nice tutorial…I really appreciate your effort!

Is it ~/.bash.rc or ~/.bashrc? Is there a file such as /etc/baash.bashrc? I can’t find /etc/bash.bashrc as well on my CoreOS machine

This was a very useful and well written tutorial, thank you!

Great tutorial. Certainly will be my refrence.

thanks the author alot! :)

Really nice job.

Nicely explained, gives me a better understanding. Thanks

Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.