cheat-sheets

Shell History

How Bash and Zsh record, search, share and clean up command history. Settings belong in bashrc or zshrc; the OMZ history plugin gives a few aliases (Oh My Zsh).

Documentation: Bash History Facilities, Zsh Options: History

Checked against Bash 5.3 and Zsh 5.9.

Search and Reuse #

COMMANDDESCRIPTION
Ctrl+R / Ctrl+SIncremental search backwards / forwards (Ctrl+S may need stty -ixon)
Up / DownStep through history
!!Previous command
sudo !!Run the previous command with sudo
!$Last argument of the previous command
!^First argument of the previous command
!*All arguments of the previous command
!N / !-NEntry number N / N entries back
!STRINGMost recent command starting with STRING
!?STRINGMost recent command containing STRING
^OLD^NEWRerun the previous command, replacing OLD with NEW
!!:s/OLD/NEW/Same, in full modifier form
Alt+.Insert the last argument of the previous command (repeat to go back)
history | grep TEXTSearch the list

Add :p to print instead of running, e.g. !!:p.

Viewing and Editing #

COMMANDSHELLDESCRIPTION
historyBashWhole history, numbered
history NBashLast N entries
history 1ZshWhole history (Zsh shows only recent entries without an argument)
history -i 1ZshWith ISO timestamps
fc -l -20BothLast 20 entries
fc -ln -1BothPrevious command without its number
fcBothOpen the previous command in $EDITOR, then run it
history -d NBashDelete entry N from memory
history -cBashClear this shell’s history
history -c && history -wBashClear memory and empty the file
fc -WZshWrite this session’s history to $HISTFILE
fc -RZshRead the history file into this session

Edit the history file directly (with no shells writing to it) to remove a line you recorded by mistake.

Bash Settings #

Put in ~/.bashrc.

SETTINGEFFECT
HISTSIZE=100000Entries kept in memory
HISTFILESIZE=200000Lines kept in ~/.bash_history
HISTCONTROL=ignoreboth:erasedupsignorespace + ignoredups, and delete older duplicates
HISTIGNORE='ls:cd:pwd:exit'Colon-separated patterns never recorded
HISTTIMEFORMAT='%F %T 'Store and show timestamps
shopt -s histappendAppend on exit instead of overwriting
shopt -s cmdhistSave a multi-line command as one entry (on by default)
PROMPT_COMMAND='history -a'Write each command to the file as it runs
PROMPT_COMMAND='history -a; history -c; history -r'Also re-read the file, to share history live across terminals

HISTCONTROL=ignorespace means a command typed with a leading space is not recorded, handy for secrets on the command line (still avoid typing secrets).

Zsh Settings #

Put in ~/.zshrc. Zsh starts with SAVEHIST=0 and no HISTFILE, so set both or nothing is saved.

SETTINGEFFECT
HISTFILE=~/.zsh_historyWhere history is saved
HISTSIZE=100000Entries kept in memory
SAVEHIST=100000Entries saved to the file
setopt EXTENDED_HISTORYSave :START:ELAPSED;command with timestamps
setopt SHARE_HISTORYShare across running shells (implies incremental append)
setopt INC_APPEND_HISTORYAppend as commands run, without sharing
setopt HIST_IGNORE_ALL_DUPSRemove older duplicates
setopt HIST_IGNORE_DUPSDo not record a command identical to the previous one
setopt HIST_IGNORE_SPACEDo not record commands starting with a space
setopt HIST_REDUCE_BLANKSTrim superfluous blanks
setopt HIST_SAVE_NO_DUPSDo not write duplicates to the file
setopt HIST_FIND_NO_DUPSSkip duplicates while searching
setopt HIST_EXPIRE_DUPS_FIRSTDrop duplicates first when the file exceeds HISTSIZE
setopt HIST_VERIFYShow !! expansions for editing before running
setopt HIST_FCNTL_LOCKUse fcntl locking on the history file

Better Search Tools #

TOOLWHAT IT ADDS
fzfCtrl+R fuzzy search; its shell integration is loaded with source <(fzf --zsh) or eval "$(fzf --bash)" on recent versions ((unverified) for your version; fzf --help lists it)
zsh-history-substring-searchUp / down arrows match what you have already typed
per-directory-history (OMZ plugin)Separate history per directory
AtuinSQLite history with sync across machines ((unverified))

Migrate Bash History to Zsh #

Zsh reads plain lines, so append the Bash file to the Zsh file once. With EXTENDED_HISTORY, plain lines are accepted, but they carry no timestamps.

bash
cat ~/.bash_history >> ~/.zsh_history

Troubleshooting #

SYMPTOMFIX
History empty after a crash or closing the terminalBash: add PROMPT_COMMAND='history -a'; Zsh: use INC_APPEND_HISTORY or SHARE_HISTORY
History lost when two terminals closeBash: set shopt -s histappend
Nothing saved in ZshSAVEHIST is 0 or HISTFILE is unset
zsh: corrupt history fileBack up the file, then try strings ~/.zsh_history > fixed and move fixed into place ((unverified))
! in a double-quoted string expandsUse single quotes, or set +H (Bash) / setopt NO_BANG_HIST (Zsh)
Secrets in historyEdit the file, then history -c (Bash) or fc -R (Zsh) to reload

See Also #

Search all sheets

Tip: / or Ctrl/Cmd+K to open, Esc to close.