Environment variables & PATH
export, $VAR, .bashrc, and how $PATH works.
Every time you open a terminal, the shell (the program that reads what you type and runs your commands) keeps a small notebook of labeled values pinned next to it. Your username. Your home folder. Which language your messages print in. Each entry is a name with a value attached, and the whole set is called the environment. The useful part: every program the shell starts gets its own copy of that notebook handed to it. So an environment variable is a labeled value, and the environment is the bag of them that travels from the shell into whatever you run.
You read one back by putting a dollar sign in front of its name. The dollar sign tells the shell "don't take this word literally, look up its value and paste it in here."
Reading What's Already There
printenv with no arguments dumps the whole notebook; give it names and it prints only those values, one per line. Get into the habit of quoting your variables ("$HOME", not $HOME). If a value ever contains a space, quoting keeps it as one piece. An unquoted value that gets split in two is a classic source of scripts that break in odd ways, and occasionally of security bugs where one filename gets read as two separate arguments.
Setting a Variable, and Why Export Is the Whole Game
Writing a variable is like jotting a note, but there are two very different places to put it. You can write it on the back of your own hand, where only you can read it, or you can pin it to the shared corkboard by the door so everyone who walks out takes a copy. In the shell, a plain assignment writes on your hand. export pins the note to the corkboard.
You set a variable with NAME=value and no spaces around the equals sign. Then export promotes it into the environment, the copy that gets handed down to every program you launch. A variable you set but never export is invisible to the command you run next, and that catches everyone at least once.
Read those two middle lines slowly. We launched a child shell and asked it for GREETING. Before export it saw nothing, an empty value. After export the exact same command saw hello. Nothing about GREETING itself changed; the only difference was whether it was pinned to the board where children can reach it. This is the number one cause of "why is my setting being ignored?": the program you ran never received the variable because it was set but not exported.
There is a shorthand for "set this for one command and one command only." Put the assignment directly in front of the command. It lives for that single run and disappears afterward, left on neither your hand nor the board.
One detail about that equals sign trips up almost everyone once: do not put spaces around it. NAME = value does not set a variable. The shell reads NAME as a command to run, with = and value as its two arguments, and hands you back "NAME: command not found." Write NAME=value with nothing touching the equals sign on either side.
PATH: How the Shell Finds the Command You Typed
When you type git, how does the shell know the actual program lives at /usr/bin/git? It doesn't, at first. It has a list of rooms to check, in order, and it walks them one at a time until it finds something called git that it can run. That list is an environment variable named PATH (short for search path). It works like telling someone "look in the junk drawer, then the office desk, then the garage, and bring me the first pair of scissors you find." The order is the entire point.
The directories are separated by colons, and the shell searches them left to right. First match wins. You can ask where a name actually resolves with which.
Adding a directory to the front of PATH means the shell finds your copy of a program before the system's. That is how you run your own tools by name, and it is also, from a security angle, exactly where things get interesting.
gitgit turns upSecurity: The Environment Is a Leaky Place
Go back to the corkboard and the list of rooms, and now ask a defender's question: who else can rearrange the rooms or leave notes? If one of the early rooms on the search list is one that other people can drop things into, someone can leave a fake pair of scissors labeled exactly like the real one, and you will grab theirs without noticing. On a computer this is called PATH hijacking, and it is a genuine way people climb from a normal account up to root (the all-powerful administrator account).
The classic setup: a job running as root calls a bare command name (backup instead of /usr/bin/backup), and its PATH contains a directory a normal user can write to, placed before the system directories. The attacker drops their own file named backup into that directory. Next time the root job runs, it finds the attacker's file first and runs it with root's powers. That is why you never put the current directory (written as . or as an empty entry) early in PATH, and why sudo (the tool that runs one command as another user, usually root) ships with its own locked-down search path.
That line tells sudo to throw away your PATH entirely and use its own fixed one, so a poisoned search path in your shell does not follow you into a root command. Good defaults like this are the quiet difference between a mistake and a breach.
A few environment variables go further than storing a value. They change how a program starts up. LD_PRELOAD (a variable that forces a program to load a code library of your choosing before its normal ones) can make a program run an attacker's code without touching the program's own files at all. That is why the program loader (the part of the system that pulls code libraries into memory as a program starts) ignores LD_PRELOAD for anything running with elevated privileges. Keep this in the back of your mind: the environment does not only hold settings. Some of it steers how your code behaves.
The other half of the danger is that exported variables spread. Every child process gets a copy, and that copy surfaces in places you did not think about. The kernel (the core part of the operating system that talks to the hardware) exposes a running program's environment through a virtual file at /proc/<PID>/environ, where PID is the process ID, the number the system assigns each running program.
We asked the kernel for our own process's environment, and there sat the password in plain text. That file is readable only by the account that owns the process and by root, so it is not quite "anyone can read it." But the list of things that quietly capture the environment is long: core dumps when a program crashes, error-reporting tools, docker inspect on a container, kubectl describe pod on a cluster, and every child process the program starts. A secret in the environment is one crash or one debug command away from ending up in a log file.
Making It Stick: Startup Files
Everything you set in a shell vanishes the moment you close the window. The environment lives inside that one process, and when the process ends, its notebook is thrown away. To have your settings appear in every new terminal, you write them into a startup file that the shell reads automatically each time it opens.
It is the difference between telling today's barista how you take your coffee and writing it on a standing order every barista already sees. For an interactive shell that is not a login (a fresh terminal tab on a machine you are already using), Bash reads ~/.bashrc. For a login shell (when you SSH, which is Secure Shell, the tool for logging into a remote machine, or when you sign in at the console), Bash reads ~/.profile or ~/.bash_profile instead, and those usually source ~/.bashrc so you end up with one set of settings everywhere.
# ~/.bashrc: read by every interactive non-login shellexport EDITOR=vimexport LESS="-R"# put your personal tools first, but only trusted directoriesexport PATH="$HOME/bin:$PATH"
After editing the file, a shell you already have open will not notice the change until you either open a new one or reload it by hand. Reloading is called sourcing: it runs the file's lines in your current shell instead of in a throwaway child, so the new values stick to the session you are in.
One real trap with PATH lines in a startup file: always build on top of the old value ("$HOME/bin:$PATH"), never replace it (PATH="$HOME/bin"). If you overwrite PATH, the shell suddenly cannot find ls, git, or anything else, and you get "command not found" for the most basic commands until you repair the file. Keep the existing value and add to it.
.:/usr/bin:/bin and you run ls inside a folder a coworker shared with you. It behaves strangely. What is the most likely explanation?. at the front of PATH, anything sitting in the current directory shadows the real command. This is exactly why the current directory should never appear early in PATH.ls itself.ls wins the search. The . at the front of PATH is the actual problem.TOKEN=abc123 and then launch a script that reads $TOKEN, but the script sees an empty value. What is the fix?DB_PASSWORD into the app's environment and argues it is safe because /proc/<pid>/environ is readable only by the owner and root. Why is keeping the secret there still risky?A habit worth keeping as you move into operations work: every so often, look at the directories in your PATH and ask whether any of them can be written to by someone other than you. This one-liner walks your PATH in order and lists each directory with its owner and permissions, so you can eyeball them.
Two of those entries, /bin and /sbin, are really symbolic links (shortcuts that point at another location) into /usr on a modern system, which is where the real files live. The capital -L in the command follows each shortcut so you check the real directory's permissions instead of the shortcut's, and -n1 keeps the listing in PATH order. What you want to see is what you see here: every directory owned by root or by you, and none of them writable by the group or by everyone else (no extra w bits in the last two permission triads). If a PATH directory ever shows up as drwxrwxrwx, that is world-writable, meaning any user on the machine can drop a command there and have it run as you. Fix the permissions or take that directory out of PATH before it becomes someone else's foothold.
Try this
Work through “Making It Stick: Startup Files” yourself on a sandbox you can throw away, following the commands above in order. Then break one step deliberately and re-run, so you have seen the failure before it finds you.
Takeaway
The trap worth remembering here: never keep real secrets in env vars or .bashrc. Check that on your own systems before you need to, because it is cheaper to find on a quiet afternoon than during an incident.