Productivity: aliases, history, xargs
Master the habits that make terminal power users fast: history navigation, aliases, command chaining, xargs, and line-editing shortcuts.
What you'll learn
- Navigate and reuse shell history with !!, !$, and Ctrl+R
- Create and persist aliases to shrink repetitive commands
- Use xargs to pipe data as arguments, safely handling tricky filenames
Before you start
Watch someone who lives in the terminal and you will notice they rarely retype anything. They summon previous commands instantly, abbreviate long invocations to two characters, and compose small tools into precise one-liners. None of this is magic — it is a handful of habits layered on three ideas:
- Recall — stop retyping things you have already typed
- Alias — name things you type often
- Compose — wire small commands together
Each section below adds one layer.
History: stop retyping commands
Your shell keeps a log of everything you run. The history command prints it:
history
498 git status
499 npm run build
500 git add -A
501 git commit -m "fix layout"
Re-run the last command with !!
!! expands to the full previous command. The classic use-case is forgetting sudo:
apt install ripgrep
# Permission denied
sudo !!
# Expands to: sudo apt install ripgrep
Reuse the last argument with !$
!$ expands to the last word of the previous command — often a filename or path.
mkdir -p src/components/Button
cd !$
# Expands to: cd src/components/Button
Ctrl+R — reverse-search (the big one)
Press Ctrl+R and start typing any fragment of a past command. The shell searches backward through history and shows the most recent match. Keep pressing Ctrl+R to cycle through older matches. Press Enter to run or any arrow key to land it on the prompt for editing.
(reverse-i-search)`docker': docker compose up -d
This single shortcut replaces memorising history numbers and is the move that most visibly separates fast terminal users from slow ones.
Aliases: name the things you type often
An alias is a short name that expands to a longer command before the shell runs it.
alias ll='ls -lah'
alias g=git
alias ..='cd ..'
alias gs='git status'
Run an alias exactly like a real command:
ll
# Same as: ls -lah
Persisting aliases
Aliases defined at the prompt vanish when the terminal closes. To keep them, add them to your shell’s startup file:
- Zsh (default on macOS):
~/.zshrc - Bash:
~/.bashrcor~/.bash_profile
# ~/.zshrc
alias ll='ls -lah'
alias g=git
alias gs='git status'
alias gc='git commit -m'
After editing, reload the file without restarting:
source ~/.zshrc
Command chaining: control what runs next
The shell uses a command’s exit status (0 = success, anything else = failure) to decide whether to run the next one.
| Operator | Meaning |
|---|---|
&& | Run next only if previous succeeded |
|| | Run next only if previous failed |
; | Always run next, regardless |
npm run build && npm run deploy
# deploy only runs if build exits 0
mkdir dist || echo "dist already exists"
# echo only runs if mkdir fails
git pull ; git status
# status runs no matter what
cd - — toggle between two directories
cd - switches back to whichever directory you were in before the last cd. Run it again and you return. It is the quickest way to shuttle between two locations.
cd ~/projects/api
cd ~/projects/web
cd - # back to ~/projects/api
cd - # back to ~/projects/web
xargs: turn stdin into arguments
Pipes send one command’s output to another command’s stdin. But many commands (like rm, cp, open) do not read from stdin — they expect arguments.
xargs bridges that gap: it reads lines from stdin and passes them as arguments to a command.
find . -name "*.tmp" | xargs rm
find prints a list of paths; xargs batches them and runs rm path1 path2 path3 ... rather than invoking rm once per file.
Placing arguments with -I {}
By default xargs appends arguments at the end. Use -I {} to control exactly where they land:
find . -name "*.log" | xargs -I {} mv {} logs/archived/
{} is replaced by each input item in turn.
Safe filenames with -print0 and -0
Filenames can contain spaces or newlines. Plain newline-splitting breaks in those cases. The safe pairing is find -print0 (null-terminate output) with xargs -0 (split on null bytes instead of newlines):
find . -name "*.tmp" -print0 | xargs -0 rm
This handles filenames like my report (draft).tmp correctly.
Line-editing shortcuts
These work in any readline-based shell (Bash, Zsh) and save reaching for the mouse:
| Shortcut | Action |
|---|---|
Ctrl+A | Move cursor to start of line |
Ctrl+E | Move cursor to end of line |
Ctrl+W | Delete the word to the left |
Ctrl+U | Cut everything to the left of the cursor |
Ctrl+K | Cut everything to the right of the cursor |
Ctrl+Y | Paste what was cut |
Ctrl+L | Clear the screen (keeps current command) |
Persistent sessions: tmux and screen
If you SSH into a remote server, your session dies the moment the connection drops. tmux and screen are terminal multiplexers that keep sessions alive on the server — you can detach, close your laptop, reconnect hours later, and find everything exactly as you left it. Running tmux is worth learning as a separate topic once the basics above are comfortable.