Read

Module 2 · Files and directories

Wildcards: *, ? and [abc]

Letting the shell build the list of file names for you: what *, ? and [...] match, who expands them, and how to preview a wildcard before it deletes something.

What you will learn

  • Match file names with `*`, `?`, `[abc]`, `[a-z]` and `[!abc]`.
  • Understand that the shell, not the command, expands wildcards.
  • Preview a pattern with `echo` or `ls` before using it with `mv` or `rm`.

Typing twenty file names is tedious; describing them is quick. A wildcard (or *glob*) is a word containing *, ? or [...] that the shell replaces with every existing name that fits the description. You write rm *.tmp; the shell turns it into rm a.tmp b.tmp cache.tmp before rm even starts. rm never sees the star. That is why wildcards work identically with every command: ls, cp, mv, rm, cat, grep…

PatternMatchesExample
*Any run of characters, including none*.txt: a.txt, notes.txt
?Exactly one character?.log: 1.log, 2.log but not 10.log
[abc]One character from the setq[12].csv: q1.csv, q2.csv
[a-z]One character from the range[0-9]*: names starting with a digit
[!abc]One character NOT in the set[!a]*: names not starting with a
~% cd /root/lab/l18/logs
logs% ls
1.log   10.log  11.log  2.log   3.log
logs% echo ?.log
1.log 2.log 3.log
logs% echo 1*
1.log 10.log 11.log
logs% echo [23].log
2.log 3.log
logs% echo *.zip
*.zip

Rules worth remembering

  • Hidden files are skipped. * does not match a leading dot, so rm * leaves .profile alone. To include them you must write the dot yourself, as in .* — careful, that also matches . and ...
  • Case matters. *.jpg does not match PHOTO.JPG; write *.[jJ][pP][gG] to catch both.
  • No match, no expansion. If nothing fits, this shell passes the pattern through unchanged, so ls *.zip complains about a file literally called *.zip.
  • Quotes switch it off. '*.txt' or "*.txt" reaches the command as a plain string. You will need that with find -name in lesson 35, where the command itself does the matching.
  • Wildcards only match existing names. cp a.txt new*.txt cannot invent a name for you.

Preview before you act

Because the shell does the expansion, you can see the exact list any command would receive by putting echo in front: echo rm /root/lab/l18/logs/?.log prints the full command without running it. ls -d PATTERN does the same and also shows directories as names instead of listing their contents. Make this a reflex before every rm or mv with a wildcard; it costs one second and it is the difference between "oops" and nothing.

Commands in this lesson

CommandWhat it does
ls *.txtEvery name ending in .txt.
rm ?.logNames with exactly one character before .log.
cp q[12].csv DIR/q1.csv and q2.csv only.
ls [!a]*Names not starting with a.
echo PATTERNPreview what a wildcard expands to.
ls -d PATTERNPreview, showing directories as names.

Quiz

  1. Who replaces `*.txt` with the list of matching names?

    • The command, for example `ls` or `rm`
    • The shell, before the command runs
    • The kernel
  2. In a directory with `1.log`, `2.log` and `10.log`, what does `?.log` match?

    • All three
    • `1.log` and `2.log`
    • Only `10.log`
  3. Does `rm *` delete `.profile`?

    • Yes, `*` matches everything
    • No, `*` does not match names starting with a dot
    • Only with `-f`
  4. Which pattern matches `q1.csv` and `q2.csv` but not `q3.csv`?

    • `q?.csv`
    • `q[12].csv`
    • `q*.csv`
  5. What is the safest way to check which files `rm /root/lab/l18/inbox/*.tmp` would delete?

    • `echo rm /root/lab/l18/inbox/*.tmp`
    • `rm -f /root/lab/l18/inbox/*.tmp`
    • `rm '/root/lab/l18/inbox/*.tmp'`

Practice

  1. Move every `.jpg` file from /root/lab/l18/inbox into /root/lab/l18/photos with one command that uses a wildcard. The other files stay in `inbox`.

  2. In /root/lab/l18/logs, delete the logs whose name is a single digit (`1.log`, `2.log`, `3.log`) with one wildcard, keeping `10.log` and `11.log`.

  3. /root/lab/l18/data holds `q1.csv` to `q4.csv`. Copy only `q1.csv` and `q2.csv` into /root/lab/l18/backup, using a bracket wildcard.

Open this lesson in the app to do the tasks in a real Linux machine and have them checked.