How to Use History Commands in Bash

How to Use History Commands in Bash

How to Use History Commands in Bash

Every command you type into Bash gets remembered, and learning to actually use that history — rather than just pressing the up arrow a dozen times — is one of those skills that quietly saves hours over time. Bash’s history system is far deeper than most people realize: fuzzy re-execution, search-as-you-type, targeted deletion, cross-session persistence, and shortcuts for repeating or modifying past commands without retyping them.

This guide covers the full range of Bash history features, from the basics to the tricks power users rely on daily.

Where Bash History Lives

By default, Bash keeps your command history in memory during a session and writes it to a file — typically ~/.bash_history — when the shell exits. Several environment variables control this behavior:

echo $HISTFILE       # path to the history file, usually ~/.bash_history
echo $HISTSIZE        # number of commands kept in memory for the session
echo $HISTFILESIZE    # number of commands kept in the history file

Viewing History

# Show the full command history with line numbers
history

# Show the last 20 commands
history 20

# Search history for lines containing "git"
history | grep git

Each line is numbered, and that number is your key to re-running any past command instantly.

Re-Running Past Commands

# Re-run command number 482
!482

# Re-run the last command
!!

# Re-run the last command that started with "git"
!git

# Re-run the last command containing "commit" anywhere in it
!?commit

!! is one of the most useful shortcuts in daily use — for example, forgetting sudo:

apt update
# Permission denied

sudo !!
# runs: sudo apt update

Searching History Interactively

The single most valuable history feature is reverse incremental search, triggered with Ctrl+R:

(reverse-i-search)`git': git commit -m "fix login bug"

Start typing any part of a past command, and Bash finds the most recent match in real time. Press Ctrl+R again to cycle to the next older match, Enter to run the found command, or Esc/arrow keys to edit it before running.

To search forward (toward more recent commands) after having gone backward, use Ctrl+S (note: this may require disabling terminal flow control with stty -ixon first, since Ctrl+S is historically bound to pausing terminal output).

Editing and Reusing Parts of Previous Commands

# Reuse the LAST argument of the previous command
mkdir new_folder
cd !$
# runs: cd new_folder

# Reuse ALL arguments of the previous command
grep "error" server.log logfile2.log
wc -l !*
# runs: wc -l server.log logfile2.log

# Substitute a word in the last command and re-run it
echo "helo world"
^helo^hello
# runs: echo "hello world"

!$ and !* are quick shortcuts for reusing the arguments of your previous command without retyping them — extremely handy when you’re doing several operations on the same file or files in a row.

History Expansion Reference

ShortcutMeaning
!!Last command
!nCommand number n from history
!-nThe nth command back from the current one
!stringMost recent command starting with string
!?string?Most recent command containing string anywhere
!$Last argument of the previous command
!*All arguments of the previous command
!^First argument of the previous command
^old^newRe-run last command, replacing “old” with “new”

Deleting Specific History Entries

# Delete entry number 245
history -d 245

# Clear the entire history for the current session
history -c

# Also remove the persisted history file
history -c && rm -f ~/.bash_history

This is especially relevant right after accidentally typing a password or API key directly into the terminal — deleting the specific entry (or the whole session’s history) prevents it from being written to disk.

Preventing a Command from Being Saved to History

Prefix a command with a space (requires HISTCONTROL to include ignorespace, which is the default on most systems):

 export API_KEY="super-secret-value"

That leading space keeps this specific command out of history entirely, which is a simple, effective habit for anything sensitive typed directly on the command line.

Useful HISTCONTROL and Related Settings

Add these to ~/.bashrc to shape how history behaves:

# Ignore duplicate consecutive commands and commands starting with a space
export HISTCONTROL=ignoreboth

# Increase history size significantly
export HISTSIZE=10000
export HISTFILESIZE=20000

# Add a timestamp to each history entry
export HISTTIMEFORMAT="%F %T  "

# Append to history file rather than overwriting it (important for multiple open terminals)
shopt -s histappend

# Save each command to history immediately, not just at shell exit
export PROMPT_COMMAND="history -a; $PROMPT_COMMAND"

How histappend and the PROMPT_COMMAND trick work together: by default, each Bash session only writes its history to disk when it closes, and does so by overwriting the file — meaning if you have two terminals open, the one that closes last wins and the other’s commands are lost. shopt -s histappend changes closing behavior to append instead of overwrite, and adding history -a to PROMPT_COMMAND writes each command to the file immediately after it runs, rather than waiting for the shell to exit at all. Together, they make history sharing across multiple simultaneous terminal sessions reliable.

Real-World Use Cases

Finding a Complex Command You Ran Weeks Ago

history | grep -i "rsync"

With HISTTIMEFORMAT set, this also shows exactly when you ran it — useful for reconstructing “what did I do to fix this last time.”

Auditing What Was Run on a Shared Server

# Combined with HISTTIMEFORMAT, gives a timestamped audit trail
cat ~/.bash_history

For genuine auditing purposes on shared/production systems, dedicated session-recording tools (like script, auditd, or a bastion host with full logging) are far more reliable than relying on .bash_history, since history files can be edited or cleared by the user.

Quickly Repeating a Build/Test Cycle

make build && ./run_tests.sh
# ... fix something ...
!!

Rapid File Operations Using Argument Reuse

touch report.txt
vim !$
chmod 644 !$

Best Practices

Security Considerations

Optimization Tips

Troubleshooting Common Issues

Problem: Commands from one terminal don’t show up in another open terminal. This is expected default behavior — each session only writes history on exit, and by default overwrites rather than merges. Enable histappend and the PROMPT_COMMAND trick described above to share history live across sessions.

Problem: !! or !$ doesn’t seem to work as expected. History expansion is disabled in some non-interactive contexts and can behave unexpectedly inside scripts — this feature is designed for interactive use. Confirm set -H (history expansion) hasn’t been disabled, which it is by default in some non-login shell configurations.

Problem: Sensitive command still appears in history despite a leading space. Check that HISTCONTROL actually includes ignorespace or ignoreboth — without it, the leading-space trick has no effect, and every command is recorded regardless.

Problem: History seems to be missing entries after a crash or forced terminal close. Since history is normally only flushed to disk at clean shell exit, an abrupt close (crash, kill -9 on the shell itself) can lose recent commands. The PROMPT_COMMAND trick that writes history after every command largely eliminates this risk.

Common Mistakes

  1. Typing secrets directly as command arguments, leaving them permanently in plaintext history.
  2. Not enabling histappend, causing lost commands when working across multiple terminal sessions.
  3. Relying only on the up arrow instead of Ctrl+R, wasting time scrolling through long histories.
  4. Assuming history -c fully erases a command from every system it may have touched (like centralized audit logging).
  5. Setting HISTSIZE too small, limiting how far back useful search and recall can reach.

Frequently Asked Questions

How do I permanently increase my history size? Add export HISTSIZE=10000 and export HISTFILESIZE=20000 (or larger values) to ~/.bashrc, then reload with source ~/.bashrc.

What’s the difference between HISTSIZE and HISTFILESIZE? HISTSIZE controls how many commands are kept in memory during the current session; HISTFILESIZE controls how many are retained in the history file on disk across sessions.

Can I remove a single embarrassing or sensitive command from history without clearing everything? Yes — find its line number with history, then run history -d <number> to remove just that entry.

Why does Ctrl+R sometimes show an old command I don’t want, and how do I search further back? Press Ctrl+R again while already in a search to cycle backward to the next older match, rather than starting a new search each time.

Summary

Bash’s history system is far more than a scrollback log — with Ctrl+R search, !!/!$/!* expansion shortcuts, targeted deletion, and settings like histappend and HISTTIMEFORMAT, it becomes a genuinely powerful tool for working faster and keeping a searchable record of what you’ve done. A few minutes configuring ~/.bashrc properly, plus building the habit of using Ctrl+R instead of the up arrow, pays off almost immediately in day-to-day terminal work.

References

Exit mobile version