3 of 4

Shell FluencyLesson 3 of 4

Globbing, expansion and quoting

Know exactly what the shell rewrites before a command runs, and quote to stop it when you must.

  • echo
  • '*'
  • {}
  • $()
  • alias
  • history
  • export
  • env

40 min5 exercises

After this lesson you can

  • Use wildcards and brace expansion to name many files at once.
  • Choose between no quotes, double quotes and single quotes on purpose.
  • Use variables, command substitution, history and aliases to work faster and make settings persistent.

The idea

Before bash runs a command it rewrites the line. This is called expansion, and it happens in a fixed order: braces, then ~ and $variables, then $(commands), then globs (wildcards) against real file names. The command never sees your wildcard; it sees the finished list. That is why echo *.txt shows you what rm *.txt would delete.

PatternMatches
*Any run of characters, including none
?Exactly one character
[abc], [a-c]One character from the set or range
{a,b,c}Brace expansion: three words, even if no such files exist
~, ~bobYour home, or bob’s home

Quoting stops expansion. Double quotes keep $variable and $(command) working but stop word-splitting and globbing. Single quotes stop everything. A backslash quotes the next character. When in doubt, quote a variable: "$file".

Try it

mkdir -p ~/lab/glob && cd ~/lab/glob
touch a.txt b.txt c.log
echo *.txt
echo ?.log
echo [ab].*
a.txt b.txt
c.log
a.txt b.txt
echo report-{jan,feb,mar}.txt
report-jan.txt report-feb.txt report-mar.txt
name="Linux Lab"
echo "Hello $name"
echo 'Hello $name'
echo "Today is $(date +%A)"
Hello Linux Lab
Hello $name
Today is Tuesday

Variables and the environment

A plain variable (name=value) lives only in this shell. export copies it into the environment of every command you start. PATH is the list of directories searched for commands, and env prints what child programs will inherit.

echo $PATH
export PATH="$HOME/bin:$PATH"
echo $PATH
/home/alex/.local/bin:/home/alex/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
/home/alex/bin:/home/alex/.local/bin:/home/alex/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

History and keyboard speed

history | tail -3
  101  echo "Today is $(date +%A)"
  102  echo $PATH
  103  history | tail -3

!! repeats the last command, !string the last one that started with string, Ctrl+R searches backwards, Tab completes names and Ctrl+C stops a running command.

Going further

Use alias name='command' for shortcuts and unalias name to remove one. \ls bypasses an alias for one run. When a wildcard matches nothing, bash passes the pattern through unchanged, so rm *.bak with no .bak files tries to remove a file literally named *.bak. Look first with echo, delete second.

Practice

0 of 5 done

Do these on your own system. They get harder. Check each result, then tick it off.

  1. Warm-up

    Watch the shell rewrite your line

    In an empty ~/lab/glob directory create a.txt b.txt c.log. Use echo (not ls) to show which names .txt, ?.log and [ab]. expand to.

    Check your result

    The three echo lines print a.txt b.txt, c.log and a.txt b.txt in that order.

    Hint

    echo prints whatever the shell hands it, so it shows the expansion.

    Solution
    mkdir -p ~/lab/glob && cd ~/lab/glob
    touch a.txt b.txt c.log
    echo *.txt
    echo ?.log
    echo [ab].*
  2. Practice

    Build a tree in one command

    With one mkdir command, create ~/lab/proj/src, ~/lab/proj/tests and, inside docs, directories 2025 and 2026. Print the directories with find.

    Check your result

    find ~/lab/proj -type d | sort lists proj, docs, docs/2025, docs/2026, src and tests.

    Hint

    Braces can nest: proj/{src,tests,docs/{2025,2026}}. Add -p so parents are created.

    Solution
    mkdir -p ~/lab/proj/{src,tests,docs/{2025,2026}}
    find ~/lab/proj -type d | sort
  3. Practice

    Three kinds of quote

    Set name to Linux Lab (it has a space). Print Hello $name with no quotes, with double quotes and with single quotes around the whole text. Describe the three results.

    Check your result

    Double quotes expand $name and keep it as one word: Hello Linux Lab. Single quotes print Hello $name literally. Without quotes the shell expands $name and then splits it into two words, which echo prints with a single space.

    Hint

    Assignments need quotes around values with spaces, and no spaces around =.

    Solution
    name="Linux Lab"
    echo Hello $name
    echo "Hello $name"
    echo 'Hello $name'
  4. Practice

    Put one command's output inside another

    Create a file in ~/lab whose name contains today's date in YYYY-MM-DD form, for example report-2026-11-03.txt, and put the host name inside it. Do not type the date.

    Check your result

    ls ~/lab/report-*.txt shows one file and cat prints the host name.

    Hint

    date +%F prints the date. Wrap a command in $( ) to use its output.

    Solution
    hostname > ~/lab/report-$(date +%F).txt
    ls ~/lab/report-*.txt
    cat ~/lab/report-*.txt
  5. Challenge

    Make a shortcut survive logout

    Make two settings available in every new login shell of your user: an alias ll2 for ls -lAh --group-directories-first, and ~/bin at the front of PATH. Prove it from a brand-new login shell, and say which files bash reads.

    Check your result

    Running bash -lc 'type ll2; echo $PATH' prints the alias definition and a path that starts with /home/alex/bin.

    Hint

    Per-user settings go in ~/.bashrc. Login shells read ~/.bash_profile, which on RHEL loads .bashrc.

    Solution
    mkdir -p ~/bin
    echo "alias ll2='ls -lAh --group-directories-first'" >> ~/.bashrc
    echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc
    bash -lc 'type ll2; echo $PATH'