zsh History: Where It Lives, Settings, Search and Clearing It
zsh saves your command history to the file named in $HISTFILE, which is almost always ~/.zsh_history. Check yours:
echo $HISTFILE
If that prints nothing, your history isn't being saved at all. zsh itself has no default history file, and SAVEHIST defaults to 0. macOS and Oh My Zsh both set it up for you, which is why most people never notice. This guide covers the settings, how to show and search history, how to clear it, and how to fix a corrupt history file.
Where zsh History Is Stored
| Setup | HISTFILE | HISTSIZE | SAVEHIST |
|---|---|---|---|
macOS (/etc/zshrc) | ${ZDOTDIR:-$HOME}/.zsh_history | 2000 | 1000 |
| Oh My Zsh | ~/.zsh_history if unset | 50000 | 10000 |
Plain zsh (zsh -f) | unset | 30 | 0 |
HISTSIZE is how many commands a running shell keeps in memory. SAVEHIST is how many it writes to the file. If you set your own values in ~/.zshrc, they win because .zshrc loads after /etc/zshrc. Oh My Zsh only raises the numbers when yours are lower.
Recommended .zshrc History Settings
These keep a long history, share it between open terminals, and skip the noise:
HISTFILE=~/.zsh_history
HISTSIZE=60000 # kept in memory; leave room above SAVEHIST
SAVEHIST=50000 # written to the file
setopt EXTENDED_HISTORY # save a timestamp with each command
setopt SHARE_HISTORY # write each command immediately and read other shells' commands
setopt HIST_IGNORE_DUPS # don't save a command twice in a row
setopt HIST_IGNORE_SPACE # don't save commands that start with a space
setopt HIST_EXPIRE_DUPS_FIRST # trim duplicates first when the history is full
setopt HIST_VERIFY # show !! and !$ expansions before running them
Reload with source ~/.zshrc or open a new terminal.
SHARE_HISTORY already appends each command to the file as you run it, so don't add INC_APPEND_HISTORY alongside it. The zsh manual says to treat SHARE_HISTORY, INC_APPEND_HISTORY and INC_APPEND_HISTORY_TIME as mutually exclusive. If you'd rather each terminal keep its own history until you ask for the others, use INC_APPEND_HISTORY instead and pull in new commands with fc -RI.
To keep only one copy of every command, swap HIST_IGNORE_DUPS for HIST_IGNORE_ALL_DUPS, which removes the older copy from the history list when a command repeats, and add HIST_SAVE_NO_DUPS so the file doesn't keep duplicates either.
How to Show zsh History
history in zsh is fc -l, and with no arguments it lists only the last 16 commands. To see everything:
history 1
The 1 means "start at event 1". Other useful forms:
history -20 # the last 20 commands
history -i 1 # everything, with ISO timestamps (yyyy-mm-dd hh:mm)
history -D -20 # the last 20, with how long each took (this shell only)
history 1 | grep ssh # every command containing "ssh"
Saved timestamps come from EXTENDED_HISTORY. With SHARE_HISTORY on, zsh writes each command before it runs, so durations in the file are always 0 and -D is only accurate for commands from the current shell. Commands saved before you turned it on have no timestamp in the file. Oh My Zsh aliases history to its own function, which already starts at event 1, so there plain history shows everything.
How to Search zsh History
-
Ctrl+Rstarts an incremental reverse search. Type part of a command and pressCtrl+Ragain to step back through older matches.Enterruns the match, andCtrl+Gcancels. If your$EDITORis vim, zsh starts in vi mode, whereCtrl+Risn't bound to search. Addbindkey '^R' history-incremental-search-backwardto~/.zshrc. -
Up arrow with a prefix. To make the up arrow only cycle through commands that start with what you've typed, add this to
~/.zshrc:autoload -U up-line-or-beginning-search down-line-or-beginning-search zle -N up-line-or-beginning-search zle -N down-line-or-beginning-search bindkey '^[[A' up-line-or-beginning-search bindkey '^[[B' down-line-or-beginning-search -
grepthe file.grep -a 'docker run' ~/.zsh_historysearches every saved command. The-amatters: zsh escapes some non-ASCII bytes, common in emoji, CJK text and em dashes, which can makegreptreat the file as binary and print nothing.-afixes that, but searches for those escaped characters still won't match. -
A history browser. I built histy-cli because
Ctrl+Ronly shows one match at a time. It shows your whole history in a terminal UI, filters it when you press/, and can sort by most frequent. Try it withnpx histy-cli.
How to Clear zsh History
zsh has no history -c like bash. To wipe the file and the current shell's memory together, which is what Oh My Zsh's history -c does:
print -n >| "$HISTFILE"
fc -p "$HISTFILE"
The first line empties the file. The second starts a fresh in-memory history tied to that file, so the shell doesn't write the old commands back when it exits. Other terminals that are still open have the old history in memory, so close them or run the same two lines in each.
To delete one command, such as a password you pasted, close your other terminals, open ~/.zsh_history in an editor, delete the line, save, and then open a new terminal. A shell that still has the line in memory can write it back to the file.
To keep a command out of history in the first place, turn on HIST_IGNORE_SPACE and start the command with a space.
Fix "zsh: corrupt history file"
This error usually appears after the machine or terminal crashes while zsh is writing the file, leaving null bytes in it. Strip them and reload:
cd ~
mv .zsh_history .zsh_history_bad
LC_ALL=C tr -d '\000' < .zsh_history_bad > .zsh_history
fc -R .zsh_history
tr removes the null bytes and leaves every command intact, including ones with non-ASCII characters. fc -R loads the repaired file into the current shell. Once new terminals open without the error, delete .zsh_history_bad.
You'll often see strings suggested for this instead. Avoid it: it cuts each command at its first non-ASCII character and drops short commands such as ls and cd.
Common Questions
Why does my history disappear when I close the terminal? Either HISTFILE is unset or SAVEHIST is 0. Set both in ~/.zshrc as shown above.
Why don't my terminals see each other's commands? Each shell reads the file when it starts. Turn on SHARE_HISTORY to pick up new commands from other terminals as you go.
Should HISTSIZE be bigger than SAVEHIST? Yes. The shell can't save more commands than it keeps in memory, and the zsh manual says HIST_EXPIRE_DUPS_FIRST needs HISTSIZE larger than SAVEHIST to have room for duplicates. Otherwise it behaves like HIST_IGNORE_ALL_DUPS once the history fills up.