datarekha

Productivity: aliases, history, xargs

Master the habits that make terminal power users fast: history navigation, aliases, command chaining, xargs, and line-editing shortcuts.

8 min read Intermediate Command Line Lesson 14 of 14

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: ~/.bashrc or ~/.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.

OperatorMeaning
&&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:

ShortcutAction
Ctrl+AMove cursor to start of line
Ctrl+EMove cursor to end of line
Ctrl+WDelete the word to the left
Ctrl+UCut everything to the left of the cursor
Ctrl+KCut everything to the right of the cursor
Ctrl+YPaste what was cut
Ctrl+LClear 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.


Quick check

0/3
Q1You just ran `git push origin main`. You want to run the same command again. Which is the shortest correct way?
Q2You add `alias rm='rm -i'` to your ~/.zshrc so rm always prompts before deleting. A colleague hands you a script that calls `rm` and expects it to run non-interactively. What problem might you hit?
Q3A teammate gives you this command: `find /var/log -name '*.gz' | xargs rm`. You notice some log filenames contain spaces. What is the safest replacement?

Sign in to track your progress

Completed lessons, your XP, level, and streak save to your account — it's free and takes a few seconds.

Explore further

Related lessons

Skip to content