Bash History Tricks: Search, Reuse and Never Lose a Command
On this page
Bash remembers the commands you type. Used well, that history is a personal notebook of every fix, one-liner and long rsync command you have ever worked out. Used with the defaults, it forgets most of it, loses commands when you have several terminals open, and fills up with ls.
This guide shows how to configure history properly and how to pull old commands back quickly.
The history command
Run history to see your numbered list of past commands. Give it a number to see only the last few:
$ history 3
501 cd ~/projects/site
502 git pull
503 history 3
The list lives in memory while the shell runs. When the shell exits, Bash writes it to the file named in HISTFILE, which is ~/.bash_history by default. Combine it with grep to find something specific:
$ history | grep certbot
Settings worth changing
Put these lines in your ~/.bashrc (see the .bashrc guide if you are not sure which file to use), then open a new terminal.
# Keep a lot more history
HISTSIZE=10000
HISTFILESIZE=20000
# Skip duplicates and commands that start with a space
HISTCONTROL=ignoreboth
# Record when each command was run
HISTTIMEFORMAT='%F %T '
# Don't record these trivial commands
HISTIGNORE='ls:ll:bg:fg:history:clear'
# Append to the history file instead of overwriting it
shopt -s histappend
What each one does:
- HISTSIZE is how many commands are kept in memory for the current session. The default is 500.
- HISTFILESIZE is how many lines are kept in the history file. When the file grows past this, the oldest lines are removed. Setting either variable to a negative number (Bash 4.3 and later) means unlimited.
- HISTCONTROL accepts
ignorespace(do not save commands that start with a space),ignoredups(do not save a command identical to the previous one),ignoreboth(both), anderasedups(remove all earlier copies of a command when it is saved again). Separate several values with colons. - HISTTIMEFORMAT makes
historyshow a timestamp usingstrftimecodes;%F %Tgives2026-10-25 14:05:09. Bash also stores the timestamps in the history file, so they survive restarts. - HISTIGNORE is a colon-separated list of patterns. A command that matches one exactly is not saved. Patterns can use
*, so'ls *'also skipslswith arguments. - histappend makes Bash add to
~/.bash_historyon exit instead of replacing it. Without it, the last terminal you close overwrites what the others saved.
With timestamps on, the output looks like this:
$ history 2
611 2026-10-25 14:05:09 systemctl restart nginx
612 2026-10-25 14:05:20 history 2
ignorespace setting gives you a simple way to keep a command out of history: type a space before it. That is useful when a command contains a token you would rather not have saved in a file, although the better habit is to avoid putting secrets on the command line at all.Searching with Ctrl+R
Press Ctrl+R and type part of any earlier command. Bash shows the most recent match as you type:
(reverse-i-search)`restart': systemctl restart nginx
Press Ctrl+R again for older matches, Enter to run the match, Ctrl+E or an arrow key to edit it first, and Ctrl+G to give up. More editing keys are in the keyboard shortcuts guide.
History expansion with !
History expansion lets you refer to earlier commands by typing a short code. Bash replaces the code when you press Enter, prints the resulting command, and runs it.
| Type | Means |
|---|---|
!! | The previous command |
!n | Command number n from the history list, for example !502 |
!-n | The command n lines back; !-1 is the same as !! |
!string | The most recent command that starts with string, for example !ssh |
!?string? | The most recent command that contains string anywhere |
!$ | The last argument of the previous command |
!^ | The first argument of the previous command |
!* | All arguments of the previous command |
A few real examples:
$ mkdir -p reports/2026
$ cd !$
cd reports/2026
$ vim /etc/nginx/sites-available/default
$ sudo !!
sudo vim /etc/nginx/sites-available/default
Running !ssh blindly can surprise you if your last ssh command was not the one you expected. Add :p to print the expansion without running it. The printed command is added to history, so you can then press the up arrow and Enter if it is right:
$ !ssh:p
ssh deploy@web01
shopt -s histverify to your ~/.bashrc and Bash will place every expanded history command on the command line for you to check, instead of running it straight away. Press Enter a second time to run it.Fixing the last command with ^old^new
Made a typo in the previous command? ^old^new reruns it with the first occurrence of old replaced by new:
$ ls /etc/hostnmae
ls: cannot access '/etc/hostnmae': No such file or directory
$ ^nmae^name
ls /etc/hostname
/etc/hostname
To replace every occurrence rather than only the first, use the longer form with the :gs modifier:
$ echo cat dog cat
cat dog cat
$ !!:gs/cat/cow/
echo cow dog cow
cow dog cow
Editing old commands with fc
fc ("fix command") is a built-in that opens history entries in your editor. Plain fc opens the previous command in $EDITOR; when you save and quit, the edited version runs. Other useful forms:
$ fc -l -5 # list the last 5 commands
$ fc 510 514 # open commands 510 to 514 in the editor, run them on save
$ fc -s red=blue # rerun the last command, replacing red with blue
Editing a range with fc is a quick way to turn a few lines of trial and error into the start of a script. If you open the editor by accident, delete everything in the file before saving and nothing will run.
Sharing history across terminals
By default each terminal keeps its own history in memory and writes it out only when it closes. Commands typed in one window do not appear in another until you open a new terminal. To save each command as soon as it runs, add history -a (append new lines to the file) to PROMPT_COMMAND:
shopt -s histappend
PROMPT_COMMAND="history -a${PROMPT_COMMAND:+; $PROMPT_COMMAND}"
That alone means you never lose history when a terminal crashes or an SSH connection drops. If you also want every terminal to see the others' commands immediately, add history -n, which reads lines from the file that this shell has not seen yet:
PROMPT_COMMAND="history -a; history -n${PROMPT_COMMAND:+; $PROMPT_COMMAND}"
Some people find fully shared history confusing, because the up arrow suddenly brings back a command from another window. Try history -a alone first. If you already use PROMPT_COMMAND for your prompt, see the prompt guide for how to keep both.
Removing entries
If you typed a password into the command line by mistake, delete that entry and write the cleaned history out:
$ history | tail -3
$ history -d 1234
$ history -w
history -d deletes one entry by number, and history -w rewrites the history file from memory. history -c clears the in-memory list entirely.
history -c followed by history -w empties your history file for good. Make a copy of ~/.bash_history first if there is anything in it you might want later.Quick reference
history 20: show the last 20 commands.- Ctrl+R: search backward through history.
!!,!$,!n,!-n,!string: reuse earlier commands and arguments.!string:p: print an expansion without running it.^old^new: rerun the last command with a substitution.fc: edit the last command in your editor.HISTSIZE,HISTFILESIZE,HISTCONTROL=ignoreboth,HISTTIMEFORMAT='%F %T ',shopt -s histappend: the settings to put in~/.bashrc.history -ainPROMPT_COMMAND: save each command immediately.
All the details, including word designators and modifiers, are in the History Expansion section of the Bash manual.