Wildcards, aliases & shortcuts

Globbing, tab-completion, history, chaining.

Beginner12 min · lesson 12 of 25

A few shell features turn slow, error-prone typing into fast, confident work — and they are the habits that separate someone fumbling at a terminal from someone flying. None are complicated; they just take a moment to learn and then save you time on every single command.

Wildcards (globbing)

The shell expands wildcard patterns into matching filenames before running the command. * matches any characters, ? matches a single character, and [abc] matches one of a set. So *.log is every file ending in .log, and the shell hands the command the actual list. This is how you act on many files at once — but it is also why a wildcard in an rm is dangerous, since it can expand to more than you expect.

terminal
$ ls *.log # every file ending in .log
app.log error.log access.log
$ ls log-2026-0?.txt # ? matches one char: log-2026-01.txt, ...-02.txt, ...
$ cp report.[tc]sv backup/ # match report.tsv OR report.csv
# tip: run ls <pattern> first to SEE what a wildcard expands to before using it with rm

Tab completion and history

Two features you should use reflexively. Tab completion: start typing a command or path and press Tab, and the shell finishes it (or shows the options) — it prevents typos and saves keystrokes. History: the up-arrow recalls previous commands, and Ctrl-R searches your history interactively (type a few characters of an earlier command and it finds it). Between them you rarely retype a long command, and you rarely misspell a path.

terminal
$ cd /var/lo<Tab> # completes to /var/log/
$ systemctl re<Tab><Tab> # shows: reload restart reset-failed ...
$ <Ctrl-R>nginx # searches history for a past command containing "nginx"
(reverse-i-search)`nginx': systemctl restart nginx # press Enter to run it

Chaining commands

You can join commands on one line with three operators, and the difference matters. ; runs them in sequence regardless of success; && runs the next one only if the previous succeeded; and || runs the next only if the previous failed. So make && ./deploy runs the deploy only if the build succeeded — a small habit that prevents acting on a broken step.

terminal
$ cd /opt/app && git pull && systemctl restart myapp
# each step runs ONLY if the previous succeeded — a failed pull stops the restart
$ mkdir build ; cd build # ; runs both regardless of success
$ ping -c1 host || echo "host is down" # || runs the second only if the first FAILED

Aliases: name your common commands

An alias is a shortcut for a longer command. alias ll='ls -lah' means typing ll runs the full command. Put your aliases in ~/.bashrc so they persist across sessions. They are a small quality-of-life win — the commands you run fifty times a day become two letters — and a way to bake in safe defaults (like making rm ask for confirmation).

~/.bashrc
alias ll='ls -lah'
alias gs='git status'
alias rm='rm -i' # make rm ASK before deleting — a cheap safety net
# reload with: source ~/.bashrc
A wildcard is expanded by the shell, so preview it
The shell replaces a wildcard with the matching filenames BEFORE the command runs, so rm *.log deletes whatever *.log expands to right now — and a stray space (rm * .log) or an unexpected match can be catastrophic. The safe habit is to run ls with the same pattern first and read the list, then run the destructive command. What you see ls print is exactly what the next command will act on.