History Tricks: !!, !$ and Ctrl+R

!! runs the last command again and !$ reuses its last argument, sudo !! repeats a command that needed sudo, Ctrl+R steps back through older matches, and four lines in ~/.bashrc keep a longer history that every terminal adds to.

Journeyman · Unix · Linux · Updated

After this lesson you can

  • Rerun the last command with !!, reuse its last argument with !$, and say what sudo !! runs
  • Keep a longer history that every terminal adds to, with HISTSIZE, HISTFILESIZE, histappend and history -a

Key takeaways

  • !! (read "bang bang") stands for the whole last command, so !! | wc -l runs it again with a pipe added. bash prints the line it made before running it.
  • !$ (read "bang dollar") stands for the last argument of the last command, so after mkdir -p and a long path, cd !$ goes into it.
  • sudo !! runs the last command again with sudo. Turn on shopt -s histverify, and bash shows you the line to check before it runs.
  • Press Ctrl+R again to step back to older matches, and the right arrow to change a match before you run it.
  • HISTSIZE and HISTFILESIZE set how many commands are kept. PROMPT_COMMAND='history -a' saves each one as soon as it runs.

You listed a folder, and now you want to count what's in it. You made a folder four levels deep, and now you want to go into it. A command failed because it needed administrator rights. Each time, the next command is mostly the last one again, and retyping it is where typos creep in. Your Command History brought commands back with the up arrow and Ctrl+R. bash also has short codes that stand for parts of your last command, and settings that make the history itself longer and safer. System administrators lean on them all day, because their commands are long and often run twice.

The examples use the practice folder from Keyboard Shortcuts at the Prompt: cd ~/terminal-practice/photo-project.

!!: the last command again

! is read "bang", so !! is "bang bang", and it stands for your whole last command. bash swaps it in before running the line, a step called history expansion. List the beach photos, then count them by adding a pipe:

ls raw/2026/05-may/beach
!! | wc -l
IMG_0501.jpg  IMG_0502.jpg  IMG_0503.jpg
ls raw/2026/05-may/beach | wc -l
3

The middle line is bash showing you the command it made from !! | wc -l, before it runs it. !! works anywhere in a line, at the start, the end or the middle.

!$: the last argument

!$, "bang dollar", stands for only the last argument of the last command: often a long path. Make a folder, then go into it without typing the path again:

mkdir -p exports/print/large
cd !$
pwd
cd exports/print/large
/home/sam/terminal-practice/photo-project/exports/print/large

Alt+. from Keyboard Shortcuts at the Prompt does the same job, but you see the path before you press Enter. !$ is fewer keys when you're sure. !! and !$ work in zsh too.

sudo !!: when a command needed sudo

Some commands change the whole computer, so Linux asks you to run them with sudo (sudo and Who Owns a File). Forget it, and the command answers with Permission denied. Typing apt update, which refreshes Ubuntu's list of software, without sudo does exactly that. sudo !! is the famous fix: it runs your last command again with sudo in front, here sudo apt update.

Because sudo runs with full rights, look before it runs. Make sure !! is the command you think it is. One setting makes bash show you: type shopt -s histverify and press Enter. From then on, a line with !! or !$ isn't run straight away. bash puts the finished line on the prompt instead:

$ sudo !!
$ sudo apt update

The second line is waiting, and nothing has run yet. Press Enter to run it (sudo asks for your password), or Ctrl+C to drop it.

Ctrl+R, further back

Ctrl+R searches your history as you type. Two more moves make it better. Run ls raw/2026/05-may/beach and ls raw/2026/04-april/park, then press Ctrl+R and type ls raw. It finds the newest match:

(reverse-i-search)`ls raw': ls raw/2026/04-april/park

Press Ctrl+R again, and it steps back to the next older match:

(reverse-i-search)`ls raw': ls raw/2026/05-may/beach

Press the right arrow to put the match on the prompt and change it before you run it, or Enter to run it as it is.

A longer history that every terminal adds to

Ctrl+R can only find what bash kept. Ubuntu's ~/.bashrc, the settings file bash reads as each terminal opens, keeps 1,000 commands in memory and 2,000 in ~/.bash_history:

grep -n -E '^HIST|histappend' ~/.bashrc
13:HISTCONTROL=ignoreboth
16:shopt -s histappend
19:HISTSIZE=1000
20:HISTFILESIZE=2000

HISTSIZE is how many commands a terminal remembers while it's open, and HISTFILESIZE how many the file keeps. histappend makes each terminal add its commands to the file instead of replacing it. But each still writes only when it closes, so a terminal that crashes loses its commands, and a new one can't find what the open ones have done. PROMPT_COMMAND runs before each new prompt, and history -a adds the new commands to the file, so together they save each command as soon as it has run. (ignoreboth leaves out repeats, and any line you start with a space.)

Back up ~/.bashrc first (cp ~/.bashrc ~/.bashrc.bak), then open it in nano and add these lines at the end. Startup Files: .bashrc, .zshrc and source covers the file in full.

# A longer history, saved after every command
HISTSIZE=10000
HISTFILESIZE=20000
PROMPT_COMMAND='history -a'

Load the changes into this terminal, and check:

source ~/.bashrc
echo $HISTSIZE $HISTFILESIZE
10000 20000

Now every command reaches the file at once:

ls exports
tail -n 2 ~/.bash_history
print  web
echo $HISTSIZE $HISTFILESIZE
ls exports

On a Mac, zsh's settings go in ~/.zshrc instead: HISTSIZE=10000, SAVEHIST=20000 and setopt INC_APPEND_HISTORY.

Check yourself

2 questions to try on the lesson page.

So what

!! and !$ reuse what you typed a moment ago, sudo !! fixes a forgotten sudo (after a look), and a longer history means Ctrl+R finds the command you ran last month.

Key terms

Cheat sheets

Related