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…
| Pattern | Matches | Example |
|---|---|---|
* | 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 set | q[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, sorm *leaves.profilealone. To include them you must write the dot yourself, as in.*— careful, that also matches.and... - Case matters.
*.jpgdoes not matchPHOTO.JPG; write*.[jJ][pP][gG]to catch both. - No match, no expansion. If nothing fits, this shell passes the pattern through unchanged, so
ls *.zipcomplains about a file literally called*.zip. - Quotes switch it off.
'*.txt'or"*.txt"reaches the command as a plain string. You will need that withfind -namein lesson 35, where the command itself does the matching. - Wildcards only match existing names.
cp a.txt new*.txtcannot 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
| Command | What it does |
|---|---|
ls *.txt | Every name ending in .txt. |
rm ?.log | Names 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 PATTERN | Preview what a wildcard expands to. |
ls -d PATTERN | Preview, showing directories as names. |
Quiz
Who replaces `*.txt` with the list of matching names?
- The command, for example `ls` or `rm`
- The shell, before the command runs
- The kernel
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`
Does `rm *` delete `.profile`?
- Yes, `*` matches everything
- No, `*` does not match names starting with a dot
- Only with `-f`
Which pattern matches `q1.csv` and `q2.csv` but not `q3.csv`?
- `q?.csv`
- `q[12].csv`
- `q*.csv`
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
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`.
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`.
/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.