Customizing the shell environment

The files bash reads when it starts, which of them apply to a login shell and which to every shell, and how to set variables, aliases and functions so they are there next time.

Lesson 1 of 2 in objective 105. Shells and shell scripting, part of LPIC-1 Exam 102-500.

Which files a shell reads depends on how you got the shell. Login shell — You got it from: A console login, or ssh; System-wide file: /etc/profile, /etc/profile.d/; Your file: ~/.bash_profile, then .bash_login, then .profile; Aliases available?: Only if that file sources ~/.bashrc. Interactive shell — You got it from: A new terminal window; System-wide file: /etc/bash.bashrc or /etc/bashrc; Your file: ~/.bashrc; Aliases available?: Yes Login shell Interactive shell You got it from A console login, or ssh A new terminal window System-wide file /etc/profile, /etc/profile.d/ /etc/bash.bashrc or /etc/bashrc Your file ~/.bash_profile, then .bash_login, then .profile ~/.bashrc Aliases available? Only if that file sources ~/.bashrc Yes
Which files a shell reads depends on how you got the shell.

Login shells and interactive shells read different files

A LOGIN shell — the one you get from a console login or an ssh session — reads /etc/profile, then the first it finds of ~/.bash_profile, ~/.bash_login or ~/.profile. An INTERACTIVE NON-LOGIN shell — a new terminal window inside an already logged-in desktop — reads ~/.bashrc and, on most distributions, /etc/bash.bashrc or /etc/bashrc. That is why a variable that works after ssh is missing in a terminal window, and it is the most common real-world symptom of this objective.

Most distributions paper over the split by having ~/.bash_profile source ~/.bashrc, so everything goes in ~/.bashrc and is read in both cases. /etc/profile.d/ is the system-wide equivalent: drop a .sh file there rather than editing /etc/profile, so a package can add settings without fighting over one file. Logout runs ~/.bash_logout.

After /etc/profile, a login shell reads only the first of these it finds. A search over 3 places, tried in this order: the first hit ends it, and everything under the one that hits is never looked at. Going down a step means no file of that name in the home directory. First, ~/.bash_profile (on most distributions this one sources ~/.bashrc); a hit there means it is read, and the two below it are never opened however much is in them. Then, ~/.bash_login; a hit there means that file is read and the search stops there. Last, ~/.profile; a hit there means that file is read and the search stops there. A miss at every one of them: Nothing of your own is read — only /etc/profile and /etc/profile.d/. ~/.bash_profile on most distributions this one sources ~/.bashrc it is read, and the two below it are never opened however much is in them no file of that name in the home directory ~/.bash_login that file is read and the search stops there ~/.profile that file is read and the search stops there Nothing of your own is read — only /etc/profile and /etc/profile.d/
After /etc/profile, a login shell reads only the first of these it finds.

What you put in them

Variables: NAME=value defines, export makes it inherited. PATH, EDITOR, LANG and PS1 (the prompt string) are the ones set most often. Aliases: alias ll='ls -l' — an alias only expands as the FIRST word of a command, and it is not inherited by scripts or subshells, which is why anything that has to work in a script belongs in a function or a real command instead.

Taking a variable away again is unset NAME, and the exam separates it from the two things that resemble it, because a program can tell all three apart. NAME= leaves the variable there holding an empty string — still exported, so a child still receives it, and anything that merely asks whether the name is set still finds it. export -n NAME removes only the export attribute: children stop seeing it, set still lists it, and it is still a variable of this shell. unset is the one that removes the name entirely, from the shell and from the environment handed to everything it starts. The exception is a variable made readonly, which cannot be unset at all — the only way out of that is a new shell.

Reading one back has three answers and the exam knows it. echo $PATH is the shell doing the work — it expands the variable and echo never sees a variable at all, which is why it prints a set-but-unexported variable that the other two cannot. printenv PATH asks for one variable by name, and printenv with no argument lists the whole environment. env also prints the environment, and its real job is running a command with a modified one — env VAR=x command — so env | grep '^PATH=' is the roundabout spelling of the same question. set is the fourth and is different again: it lists shell variables AND functions, exported or not.

Functions are defined as name() { …; } and behave like commands, taking $1, $2 and so on. Both aliases and functions are shell-local, so they must be defined in a file the shell reads rather than exported. source FILE (or its synonym . FILE) runs a file in the CURRENT shell rather than a child, which is the whole reason it exists: a script that sets a variable in a child shell changes nothing, and sourcing it changes your shell.

/etc/skel is the template for new accounts — whatever is in it is copied into a new user's home directory when the account is created, which is how every new user gets a sensible .bashrc.

Four ways to read a variable back, and what each one can see. echo $VAR — Who expands it: The shell; Sees unexported vars: Yes; Also lists functions: No. printenv VAR — Who expands it: The command; Sees unexported vars: No; Also lists functions: No. env — Who expands it: The command; Sees unexported vars: No; Also lists functions: No. set — Who expands it: The shell; Sees unexported vars: Yes; Also lists functions: Yes echo $VAR printenv VAR env set Who expands it The shell The command The command The shell Sees unexported vars Yes No No Yes Also lists functions No No No Yes
Four ways to read a variable back, and what each one can see.

Worth carrying in

~/.bash_profile
Login shells. Usually just sources ~/.bashrc.
~/.bashrc
Interactive non-login shells. Aliases and functions belong here.
/etc/profile
System-wide login. Add files to /etc/profile.d/ rather than editing it.
source file / . file
Run a file in the current shell so its settings persist.
alias ll='ls -l'
Only expands as the first word; not inherited by scripts.
name() { …; }
A shell function: takes $1, $2, and works where an alias will not.
/etc/skel
Copied into every new user's home directory at account creation.
echo $PATH
The shell expands it before echo runs, so this works on unexported variables too.
printenv
The environment. printenv NAME prints one; with no argument, all of it.
env
Prints the environment, or runs a command with a changed one: env VAR=x cmd.
unset NAME
Removes the variable outright. NAME= leaves it set and empty; export -n only stops it being inherited.

What the exam does with this

Objective
105. Shells and shell scripting
Share of the exam
15% (the whole objective)
Questions in this lesson
22
Signed for by a person
0

Partly checked. None of the 22 questions here has been read against the cited source by a person. 22 questions have been checked against their cited clause by an automated pass — which is not the same thing, and is not a signature.

Only questions a person has signed for are used in mock exams here. That is the whole difference between the two kinds of checking above.

How these questions are written — where each question comes from, what the verification ledger records, and what happens when one is found wrong.

Drill this lesson

A lesson is one sitting: the trainer draws a short run from these questions alone and spaces the ones you get wrong.

Practise Customizing the shell environment

Questions in this lesson

Practise Customizing the shell environment

The rest of objective 105