Wildcards, aliases & shortcuts
Globbing, tab-completion, history, chaining.
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.
$ ls *.log # every file ending in .logapp.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.
$ 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.
$ 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).
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