Bash History Explained
Bash remembers nearly everything you type, and most of the friction in using that history productively comes down to knowing a handful of shortcuts: searching it interactively, re-running recent commands without retyping them, and understanding what actually gets recorded and why.
Viewing your history
history
Prints your command history with a number prefix for each entry. By default this shows the full remembered history for the session, piped through no pager, so it is common to combine it with less or grep for a long history:
history | grep ssh
history | tail -20
Reverse search: the fastest way to reuse a command
Press Ctrl+R and start typing part of a command you remember running:
(reverse-i-search)`ssh': ssh user@server.example.com
Bash searches backward through history and shows the most recent match live, updating as you type more characters. Press Ctrl+R again to cycle to the next older match if the first one is not what you wanted. Press Enter to run the displayed command immediately, or the right or left arrow key to drop into normal editing mode with that command loaded, letting you modify it before running.
This is, in practice, the single most useful history feature for everyday terminal use, far faster than scrolling with the up arrow through dozens of commands to find one from earlier in the session.
History expansion: !! and friends
Bash’s ! character introduces history expansion, a shorthand for referring to previous commands without retyping them.
!! # repeat the immediately previous command
sudo !! # repeat the previous command, with sudo prepended
sudo !! is the most commonly used form in practice: running a command, getting a permission-denied error, and re-running it with sudo prepended without retyping the whole thing.
!ssh # repeat the most recent command starting with "ssh"
!482 # repeat command number 482, as shown by history
!-2 # repeat the command two before the current one
!$ # the last argument of the previous command
!$ is worth calling out specifically: it expands to just the last argument of the previous command, which is useful when you want to reuse a filename or path you just referenced without retyping it:
mkdir /var/backups/project-2026
cd !$
# expands to: cd /var/backups/project-2026
What actually gets saved, and what doesn’t
Two variables control what history records. HISTCONTROL can be set to ignoredups (skip immediately repeated duplicate commands), ignorespace (skip any command that starts with a leading space), or ignoreboth (both at once):
export HISTCONTROL=ignoreboth
ignorespace is a deliberate feature: prefixing a sensitive command with a leading space excludes it from history entirely.
mysql -u root -pMyActualPassword
With a leading space and ignorespace (or ignoreboth) set, this specific command is not recorded, while normally typed commands continue to be saved as usual. This helps avoid leaving a password sitting in plain text in your history file, though the more robust fix is avoiding putting secrets directly on a command line at all, since they remain visible to other users on the system via ps while the command is actually running, regardless of what history records afterward.
Why history sometimes seems incomplete
History is normally written to the history file (~/.bash_history by default) when a shell exits cleanly, not continuously as you type. A terminal that crashes or a shell process that gets killed can lose recent commands that were never flushed to disk.
history -a
-a manually appends the current session’s history to the history file immediately, without waiting for the shell to exit, useful if you want to make sure recent commands are saved before doing something risky that might crash the session.
Controlling how much history is kept
export HISTSIZE=10000 # commands kept in memory for the current session
export HISTFILESIZE=20000 # commands kept in the history file on disk
Add both to ~/.bashrc to make the change permanent across sessions. HISTFILESIZE is typically set equal to or larger than HISTSIZE, since the file is what actually persists history between separate login sessions, while HISTSIZE only governs what is available in-memory for the currently running shell.
export HISTTIMEFORMAT="%F %T "
HISTTIMEFORMAT adds a timestamp to each entry shown by history, which is not enabled by default but is useful for auditing when a specific command was actually run, particularly on shared or production systems.
Frequently Asked Questions
How do I search my command history without scrolling through it manually?
Press Ctrl+R to start a reverse incremental search, then start typing part of a command you remember running. Bash searches backward through your history and shows the most recent match as you type, updating live with each keystroke. Press Ctrl+R again to cycle to the next older match if the first one shown is not the one you want, and press Enter to run the displayed command, or the right arrow key to edit it first without running it immediately.
What does !! do in Bash?
!! repeats the immediately previous command exactly as it was typed. It is most commonly used to re-run a command with sudo after forgetting it the first time: sudo !! re-runs the last command with sudo prepended, without needing to retype the whole thing. More generally, ! introduces Bash’s history expansion syntax, and !! specifically refers to “the last command,” one specific case among several other numbered and pattern-based history references.
How do I run a specific command from my history by its number?
First find the number with history, which lists past commands with a number prefix, then run !N, substituting the actual number, such as !482 to re-run command number 482 exactly as it was recorded. Negative offsets also work: !-2 runs the command two before the current one. This is less commonly used than Ctrl+R search or !! in practice, since it requires already knowing or looking up the specific number, but it is precise when you need to target an exact historical command.
Why does my Bash history not include every command I type?
A few common reasons: HISTCONTROL may be set to ignoredups (skip consecutive duplicate commands) or ignorespace (skip any command that starts with a leading space, a deliberate feature for excluding sensitive commands like ones containing a password from being recorded), or both, via ignoreboth. Separately, history is only written to the history file at certain points, normally when a shell session ends normally, so a crashed terminal or a killed shell can lose recent history that was never flushed to disk. Running history -a manually flushes the current session’s history to the file immediately, without waiting for the shell to exit.
How do I prevent a specific command from being saved to history?
If HISTCONTROL includes ignorespace (or ignoreboth), start the command with a leading space: a space followed by mysql -u root -pMyPassword excludes that specific command from being saved to history, while commands typed normally are still recorded as usual. This is commonly used for one-off commands that contain a password or other sensitive value directly on the command line, though the more robust fix is avoiding putting secrets on the command line at all, since they remain visible to other users on the system via ps while the command is running, regardless of whether history records them afterward.
How do I increase or decrease how much history Bash remembers?
HISTSIZE controls how many commands are kept in memory during the current session, and HISTFILESIZE controls how many commands are kept in the history file (~/.bash_history) on disk across sessions. Set both in ~/.bashrc to make the change permanent: export HISTSIZE=10000 and export HISTFILESIZE=20000, then either open a new terminal or run source ~/.bashrc to apply the change immediately. The file size limit is typically set equal to or larger than the in-memory size, since the file is what actually persists your command history between logins.