Environment Variable Zoo

Date: , Updated: — Topics: , — by Slatian

Environment variables are basically inherited, named arguments to processes with a huge impact on how a Linux or other *nix systems work.

Reading and Writing Environment Variables

These commands here should work in almost all shells inspired by the original sh, if you use something else you probably know why and how to use it.

Read out a single Variable
echo "$SHELL"
printenv SHELL
Dump out all variables
export
printenv
Set one or more variable for a single command
TZ=UTC LANG="de_DE.UTF-8" date
env TZ=UTC LANG="de_DE.UTF-8" date Useful program for simpler shells, environment (un)setting and chain-loading.
Set a variable for the currently running shell
export TZ=UTC
declare -x TZ=UTC

Persisting Environment Variables

For permanently setting some environment variables there are a number of options (Options further up usually can override the ones below them).

.bashrc, .zshrc, etc.
Read whenever you start your favourite shell (as a non-login shell), but don't assume it has effects on the whole session, it is not made for that.
Your Desktop Environment
Desktops like setting environment variables derived from their settings, sometimes for single programs, sometimes for the whole session.
.profile
Read on every login (your login manager is responsible for doing this) and applies to your whole session.
/etc/profile.d/ and /etc/profile
System-wide .profile equivalent, remember that you are sharing this one with your packages.
PAM
PAM also sets environment variables.

The .bashrc (plus friends) and .profile can be reloaded by running source ~/<filename> or . ~/.filename.

Note: Non POSIX shells usually have their own .profile equivalent, keep that in mind when changing your login shell. Bash for example uses .bash_profile if it exists.

Spying on other Processes

Sometimes it is useful to know what environment variables a given running process has currently set, if the process belongs to you or you have root rights (use them responsibly) you have access to the file that contains the process environment.

The files path is /proc/$pid/environ (Substitute $pid for the process id), it contains the null separated environment variables.

To get them in a pretty way one can use the command tr '\0' '\n' < /proc/$pid/environ (pipe it into the tr command which replaces the null separators with newlines).

htop shows the selected processes environment when pressing e.

Note: This is the reason why it usually is a bad idea to use environment variables for secrets, they can be read out by any other process running under the same user. When transporting secrets from one program to another use pipes and features of your shell to directly read from and write to them.

Finding Documentation

Outside of the usual online sources: Read the documentation and read the manpages. Most manpages have an ENVIRONMENT section describing which variables the program reads and/or sets.

environ(7) - The manpage about the basics of environment variables.

Linux and Posix

You can find a more complete list of the standardised variables in the POSIX (2017, the latest at the time of writing) specification.

HOME
Contains the path to your home directory, as simple as that. (Don't abuse for constructs like $HOME/.config/whatever, that's what the XDG home variables are for.)
PATH
Contains a colon separated list of paths to directories that contain binary files for running them as commands. Directories closer to the front can override others counting binaries of the same name further back.
USER
Should contain the currently logged in username. (Fun fact: the kernel doesn't know your username)
SHELL
Contains the path to the shell binary configured for the current user, this is probably how your favourite terminal emulator knows about your favourite shell without configuration. This may or may not be the shell you are currently using.
TMPDIR or TMP or TEMP
Almost always one of them contains a path to the preferred temporary directory. Useful for when every user gets their own directory with proper permissions. TMPDIR is the one in the POSIX standard and should be the preferred one.
LC_*
These contain locale information and are the reason why language settings work across desktop environments. Unfortunately also the reason why you have to restart applications after changing system preferences. For possible values see /etc/locale.gen and /etc/locale.conf.
LANG
Language setting, not prefixed by LC_ for reasons. Set to C for "no translation at all", usually that means American English. For possible values see /etc/locale.gen and /etc/locale.conf.
TZ and TZDIR
These describe the current timezone to use i.e. Europe/Berlin. Usually points to a tzfile in /usr/share/zoneinfo/
PAGER
A program that can be run using sh -c that shows a textfile (unually in the current terminal)
EDITOR
Like PAGER, but for your favourite text editor.
BROWSER
Like BROWSER, but for your favourite browser. (Not standardised anywhere, but a well known convention)
MAILER
Like PAGER but for opening mailto: links with your favourite E-Mail writer. (Also never standardised)
TERM
Contains the name of the terminal, together with the terminfo database the capabilities of the terminal can be found out. When remoting into other machines with a less well known terminal xterm is usually a sane fallback.
MOTD_SHOWN
When set it indicates who has already shown the motd to prevent showing it twice. Convention, probably best known implementation is the pam motd module.
NO_COLOR
When set to a non-empty string Software shouldn't use ANSI-colors unless explicity configured to do so. See no-color.org

Note: What is meant by run with sh -c is demonstrated pretty well by debians sensible-utils. In a nutshell you lauch your favorite EDITOR using sh -c "$EDITOR \"\$@\"" EDITOR <filepath-goes-here>

Note: I'm trying to move the BROWSER and MAILER variables to the XDG section. See the related discussion on the xdg mailing list. You'll have to dig around a bit to find all mails 😞.

XDG freedesktop.org

freedesktop.org hosts quite a few specifications ensuring interoperability of free (software) desktop envoirnments, these specifications happen to contain quite a lot of envoirnment variables.

XDG stands for Cross Desktop Group.

Base Directories

These are defines in the Desktop Base Directories Specification, while the below is an overview and you should always read the specification.

Note: while one can usually guess where those directories are, it is always a good idea to respect the environment variables instead of blindly writing to some guessed default path, People trying to organise their Home folder will thank you.

XDG_DATA_HOME
Path where applications can dump their non-configuration and non-cache persistence.
Default: $HOME/.local/share
XDG_CONFIG_HOME
Path for storing configuration files (and nothing else!)
Default: $HOME/.config/
XDG_DATA_DIRS
colon : separated list of fallback directories for XDG_DATA_HOME containing default data files. (similar to how $PATH works)
Default: /usr/local/share/:/usr/share/
XDG_CONFIG_DIRS
colon : separated list of fallback directories for XDG_CONFIG_HOME containing default configuration files. (similar to how $PATH works). This behaviour is very useful when administrating large desktop systems.
Default: /etc/xdg/
XDG_CACHE_HOME
Path for storing cache files, may contain files specific to the current architecture details, may need cleaning up when on a shared filesystem.
Also be used for files that better get lost rather than ending up in a backup by accident, keepassxc is an example for that.
Default: $HOME/.cache/
XDG_RUNTIME_DIR
For temporary runtime files like sockets, pipes, etc.
Usually: /run/user/<userid>/

User Directories

There is also the possibility to define User directories, these have the form of XDG_<name>_DIR and are configured using the $XDG_CONFIG_HOME/user-dirs.dirs and taken care of by the xdg-user-dirs-update utility

Commonly specified ones are:

Current Desktop

The Freedesktop "Desktop Entry Specification" specifies a XDG_CURRENT_DESKTOP variable that is set from the DesktopNames value in desktops session file (the ones in /usr/share/xsessions/ and /usr/share/wayland-sessions/ and whatever XDG_DATA_DIRS points to).

It contains a colon separated list of names for the current desktop, primarily intended for activating or deactivating desktop entries (i.e. you don't want the gnome settings cluttering up you KDE menus and vice versa).

XDG Session

These variables are not part of a specification, the best source for them is a guide for "Writing Display Managers" with systemd and the manpage for the pam_systemd module. Some of them happen to be useful.

XDG_SEAT
By definition set to seat0, probably reserved for future use in multiseat scenarios.
XDG_SESSION_TYPE
The best documentation for this one is probably the type argument for the pam_systemd module, roughly it is the display server used for the session. (x11,wayland,mir,tty,unknown)
XDG_SESSION_CLASS
either user or greeter depending on whether the session is primarily logged in or for logging in.
XDG_VTNR
set to the number of the TTY the current session runs in.
XDG_SESSION_ID
Either the /proc/self/sessionid of the auditing session or an "independent counter".

Graphical Environment

DISPLAY
The id of your X-Display, on your laptop it is probably :0.
WAYLAND_DISPLAY
The name of your wayland socket file in $XDG_RUNTIME_DIR/.
XCURSOR_SIZE, XCURSOR_THEME, XCURSOR_PATH
One way to configure how your cursor looks in most applications. It even works with wayland for when other options are not available. The Arch Wiki has more information on cursor configuration.
DBUS_SESSION_BUS_ADDRESS
Contains information on how to connect to the dbus session bus. Usually set by the dbus-run-session wrapper.

Java

_JAVA_AWT_WM_NONREPARENTING
Tells java if you have a non-reparenting window manager, usually set to 0 on modern Xorg, to 1 on wayland. If your window stays blank that is an indicator this one is wrong. (Yes the underscore at the start is intentional.)
Possible Values: 0, 1

More Java environment variables will be added when I run into them.

Kubernetes

KUBECONFIG
The path to a yaml file containing connection information for a Kubernetes cluster that tools like kubectl and helm can use to connect to the cluster.
k3s generates a /etc/rancher/k3s/k3s.yaml file you can point this at.