The shell is the unsung hero of your Linux experience. Sitting between you and the programs your operating system runs, the shell is a user interface and a programming language rolled into one.
One of the shell’s responsibilities is to apply various expansions to the command you type, inserting variables, for example. Expansion involves several steps, though, so it’s worth understanding the process in full.
Brace expansion
The very first step is to take brace expressions and turn them into strings with an optional prefix and suffix. This is useful to generate longer lists of words based on a simple pattern. For example, the first type of brace expansion uses commas to separate alternatives:
echo a{b,c}deYour shell will expand this toecho abde acde.
Using echo like this lets you see the final result after expansion.
The other type of brace expansion uses a sequence expression:
$ echo a.{1..5}.za.1.z a.2.z a.3.z a.4.z a.5.zIn this case, {1..5} is short for {1,2,3,4,5}. You can also use letters instead of numbers.
Tilde expansion
In its most basic form, the tilde character is a shortcut for your home directory, e.g.
$ echo ~/Users/bobbyThere are more tilde expansions besides this, however, for example:
- ~user expands to the path of that user’s home directory.
- ~+ expands to thecurrent working directory (PWD).
- ~- expands to the previous working directory (OLDPWD).
Parameter and variable expansion
To access a variable, use a $ followed by its name or, if it’s a positional parameter (used in shell scripts and functions), its number.
echo $PATHfoo() { echo $1 } && foo helloIn most cases, you should enclose the variable name with braces:
echo ${PATH}This helps prevent a bunch of errors, and also prepares you to use one of the many advanced types of parameter expansion that Bash supports. For example, you can set a variable to a default value if it’s unset or null, using the:- syntax:
LOCAL_PATH=${PATH:-/bin}You can also carry out basic string manipulation using substring expansion:
$ GREETING="Hello, world"$ echo ${GREETING:7}worldYou can even convert a string to uppercase or get its length:
$ TITLE="lowercase"$ echo ${TITLE@U}LOWERCASE$ echo ${#TITLE}9Bash supports many other types of parameter expansion, so it’s worth exploringits string manipulation features.
Command substitution
Command substitution is one of the most convenient upgrades you can make to your daily shell life, especially if you’re writing scripts. In simple terms, it looks like this:
echo $(ls)Bash will run the command in a subshell, replacing the original $(...) with its output. This is often useful when the command outputs a filename. For example, the mktemp command creates a temporary file and outputs its name. So, to start editing a temporary file with a single command, you can run:
vi $(mktemp)Or you can create and enter a temporary directory with:
cd $(mktemp -d)Process substitution is another type of expansion that looks a bit like command substitution. However, it’s quite different from the others on this list, and isn’t available on every system.
Arithmetic expansion
You’ll probably find arithmetic is of most use in certain types of shell scripts. The trickiest thing about arithmetic expansion is remembering the double-bracket syntax:
$(( 11 * 42 ))Other than that, you can carry out all basic integer arithmetic that you’d expect: multiplication, post-increment, and bitwise shifts, for example. You can also use standard comparison operators like == for equality and logical operators like && for AND.
Word splitting
At this point, the shell splits the results of previous expansions that did not occur between double quotes into words. It splits on characters from the IFS variable, which are typically space, tab, and newline.
Take this example:
FILES="one two three"ls ${FILES}Bash will initially replace the second command with "ls one two three". Since that expansion was not double-quoted, word splitting will result in three parameters passed to ls: one, two, and three. If the expansion were quoted, however, it would be a different story:
FILES="one two three"ls "${FILES}"In this case, ls will complain about a missing file named "one two three". This emphasizes the difference between three arguments separated by spaces and one single argument that contains spaces.
Filename expansion
Filename expansion, otherwise known as globbing, lets you match files using patterns. Even if you’ve never heard of globbing or filename expansion, you’ve probably used it before, like this:
ls *.txtWith this form of expansion, the shell looks for unquoted cases of the *, ?, and [ characters. If it finds one, it treats that word as a pattern and replaces it with all matching filenames.
While * matches any number of characters, ? matches a single character, and [...] matches a character from the given set.
Quote removal
Finally, quotes (and the backslash character, which can be used to escape them) are removed from any part of the original string before expansions.
This lets you quote arguments that you want treated as a single argument, even if they contain spaces. So, to list a problematically-named file:
ls "a filename with spaces"Without quotes, ls will try to list four separate files with single-word names.











