history Command

Command History Management and Manipulation

history [n]
history -c
history -d offset
history -a | -w | -r filename

Overview

The history command is a bash shell builtin that displays and manipulates the command history - the list of commands you've previously executed in the shell. This powerful feature allows you to review, search, and re-execute previous commands, dramatically improving efficiency and reducing typing errors.

The shell maintains command history in memory during your session and typically saves it to a file (~/.bash_history by default) when you exit. The history command provides fine-grained control over this history, including viewing, editing, clearing, and executing previous commands. Mastering history management is essential for productive command-line work.

Key Characteristics

Property Description
Type Shell builtin (bash)
History File ~/.bash_history (configurable with $HISTFILE)
Default Size 500-1000 commands (configurable with $HISTSIZE)
Numbering Each command has a sequential number
Multiple Shells: Each shell session maintains its own history in memory. When you exit, the history is written to ~/.bash_history. If you have multiple terminals open, only the last one to close will save its history (by default), potentially overwriting earlier sessions. Use history -a to append current session history to the file immediately.

History Environment Variables

Variable Purpose Default Value
HISTFILE Location of history file ~/.bash_history
HISTSIZE Number of commands in memory 500 or 1000
HISTFILESIZE Max lines in history file 500 or 1000
HISTCONTROL Control what's saved ignorespace or ignoredups
HISTIGNORE Patterns to exclude from history Not set
HISTTIMEFORMAT Timestamp format for history entries Not set (no timestamps)

Detailed Examples

Example 1: Basic History Viewing

$ history
498 cd /var/log
499 ls -la
500 tail -f syslog
501 cd ~
502 vim .bashrc
503 history

# Show last 10 commands
$ history 10
494 sudo systemctl restart apache2
495 ps aux | grep apache
496 netstat -tulpn | grep :80
497 cd /etc/apache2
498 cd /var/log
499 ls -la
500 tail -f syslog
501 cd ~
502 vim .bashrc
503 history 10

# Show last 5 commands
$ history 5
499 ls -la
500 tail -f syslog
501 cd ~
502 vim .bashrc
503 history 5
Explanation: The basic history command displays all commands in your current session's history, with each command preceded by its history number. You can specify a number to see only the last N commands: history 10 shows the last 10 commands. The history numbers are sequential and unique within your session, starting from where your history file left off. These numbers are used for history expansion (repeating commands).
Quick Tip: Use history | tail -20 or history 20 to see recent commands without scrolling through hundreds of entries.

Example 2: Searching History with grep

# Find all commands containing "apache"
$ history | grep apache
423 sudo systemctl start apache2
456 sudo systemctl stop apache2
494 sudo systemctl restart apache2
497 cd /etc/apache2
521 history | grep apache

# Find commands with "docker" (case insensitive)
$ history | grep -i docker
385 sudo docker ps
386 sudo docker images
401 sudo DOCKER pull nginx
425 sudo docker-compose up -d

# Find the last time you used ssh
$ history | grep "ssh " | tail -5
234 ssh user@server1
267 ssh root@192.168.1.100
389 ssh -i ~/.ssh/mykey.pem ec2-user@aws-server
445 ssh user@server1
498 history | grep "ssh " | tail -5

# Search and exclude the search command itself
$ history | grep apache | grep -v grep
Explanation: Combining history with grep is one of the most useful techniques for finding commands you've run before. This is especially helpful when you remember part of a command but not the exact syntax or all the options. The -i flag makes grep case-insensitive, which is useful when you're not sure of the capitalization. Using tail limits results to the most recent matches. The technique of piping through grep -v grep excludes the search command itself from the results.
Better Way: Instead of history | grep, use Ctrl+R for interactive reverse search. Start typing and it will find matching commands as you type.

Example 3: Executing Commands from History

$ history
500 ls -la /var/log
501 cd /etc
502 cat /etc/hosts
503 ping google.com
504 history

# Execute command number 502
$ !502
cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
...

# Execute the last command
$ !!
cat /etc/hosts
...

# Execute the last command that started with "ping"
$ !ping
ping google.com
PING google.com (142.250.80.46) 56(84) bytes of data.
...

# Execute last command containing "etc"
$ !?etc
cat /etc/hosts
...

# Execute command 500 but replace part of it
$ !500:s/log/www/
ls -la /var/www
Explanation: History expansion allows you to re-execute previous commands without retyping them. !N executes command number N from history. !! repeats the last command (useful for sudo !! when you forget sudo). !string executes the most recent command starting with "string". !?string finds the most recent command containing "string" anywhere. The substitution syntax !N:s/old/new/ repeats command N but replaces "old" with "new". These are powerful shortcuts that significantly speed up command-line work.
Warning: Be careful with history expansion, especially !string - it executes immediately without showing you what command it found. Use caution with potentially destructive commands. Consider using :p modifier to print without executing: !502:p

Example 4: Interactive History Search with Ctrl+R

# Press Ctrl+R to enter reverse search mode
$ Ctrl+R
(reverse-i-search)`':

# Start typing to search
(reverse-i-search)`ssh': ssh user@server1

# Press Ctrl+R again to see previous match
(reverse-i-search)`ssh': ssh root@192.168.1.100

# Press Ctrl+R again
(reverse-i-search)`ssh': ssh -i key.pem user@aws

# Press Enter to execute, or Ctrl+G to cancel
# Press Right Arrow or Ctrl+O to edit before executing

# Search forward with Ctrl+S (may need to disable flow control first)
$ stty -ixon # Add to .bashrc to make permanent
$ Ctrl+R # search backward
$ Ctrl+S # search forward
Explanation: Ctrl+R activates reverse incremental search through your command history. As you type characters, it shows the most recent command matching what you've typed. Press Ctrl+R repeatedly to cycle through older matches. This is the most efficient way to find and re-execute commands - much better than scrolling through history output. Enter executes the command immediately, Right Arrow or Ctrl+O places it on the command line for editing, and Ctrl+G cancels the search.
Pro Tip: Add stty -ixon to your ~/.bashrc to enable Ctrl+S for forward search. By default, Ctrl+S is used for flow control (freezes terminal) which is rarely needed on modern systems.

Example 5: Clearing and Managing History

# Clear all history in current session
$ history -c
$ history
1 history

# Delete specific history entry (number 523)
$ history | grep password
523 mysql -u root -p password123
$ history -d 523

# Delete a range of entries
$ for i in {520..530}; do history -d 520; done

# Clear history and the history file
$ cat /dev/null > ~/.bash_history
$ history -c

# View and manually edit history file
$ vim ~/.bash_history
# Delete lines you don't want saved

# Reload history from file
$ history -r

# Append current session history to file immediately
$ history -a

# Write current session history to file (overwrites)
$ history -w
Explanation: The -c option clears all history from the current session's memory, useful when you want a fresh start or have executed sensitive commands. -d N deletes a specific history entry by number - essential for removing commands with passwords or sensitive data. -a appends the current session's new commands to the history file, useful in multi-terminal scenarios. -w writes the entire current history to the file (overwriting it). -r reads from the history file into the current session. You can also manually edit ~/.bash_history to remove unwanted commands permanently.
Security: If you accidentally typed a password in a command, immediately delete it from history with history -d N and consider changing that password. Remember that other users with access to your account can read your history file.

Example 6: Configuring History Behavior

# Add these to ~/.bashrc for permanent settings

# Increase history size
export HISTSIZE=10000 # Commands in memory
export HISTFILESIZE=20000 # Lines in history file

# Add timestamps to history
export HISTTIMEFORMAT="%F %T "

# Now history shows timestamps
$ history 5
496 2024-11-24 08:30:15 cd /var/log
497 2024-11-24 08:31:22 tail -f syslog
498 2024-11-24 08:35:10 systemctl status apache2
499 2024-11-24 08:36:45 history 10
500 2024-11-24 08:37:12 history 5

# Don't save duplicate commands
export HISTCONTROL=ignoredups

# Don't save commands starting with space
export HISTCONTROL=ignorespace

# Combine both (ignore duplicates and space-prefixed)
export HISTCONTROL=ignoreboth

# Ignore specific commands
export HISTIGNORE="ls:ll:history:exit:clear"

# Append to history file instead of overwriting
shopt -s histappend

# Save multi-line commands as one entry
shopt -s cmdhist
Explanation: These environment variables and shell options control history behavior. HISTSIZE and HISTFILESIZE control how many commands are kept (default is often too small). HISTTIMEFORMAT adds timestamps to each command, invaluable for auditing and troubleshooting. HISTCONTROL filters what gets saved: ignoredups prevents consecutive duplicate commands from being saved, ignorespace excludes commands starting with a space (useful for sensitive commands), and ignoreboth combines both behaviors. HISTIGNORE excludes specific commands. The histappend option makes bash append to the history file rather than overwriting it, preserving history across multiple terminal sessions.
Recommended ~/.bashrc Settings:
export HISTSIZE=10000
export HISTFILESIZE=20000
export HISTCONTROL=ignoreboth
export HISTTIMEFORMAT="%F %T "
shopt -s histappend
shopt -s cmdhist

Example 7: Using History with Argument Designators

$ echo hello world testing
hello world testing

# Get the last argument of previous command
$ echo !$
echo testing
testing

# Get all arguments of previous command
$ cat /etc/hosts
$ vim !*
vim /etc/hosts

# Get specific argument (0=command, 1=first arg, etc)
$ ls -la /var/log /etc
$ cd !:2
cd /etc

# Get first argument
$ chmod 644 file1.txt file2.txt
$ vim !^
vim file1.txt

# Get range of arguments
$ cp file1 file2 file3 /backup/
$ ls !:1-3
ls file1 file2 file3

# Useful pattern: make directory and cd into it
$ mkdir /path/to/newdir
$ cd !$
cd /path/to/newdir
Explanation: Argument designators let you reference specific parts of previous commands. !$ represents the last argument of the previous command (extremely useful). !* represents all arguments. !^ is the first argument. !:N gets the Nth argument (0 is the command itself). !:N-M gets a range of arguments. These are powerful shortcuts that eliminate repetitive typing, especially for long filenames or paths. The mkdir/cd pattern using !$ is one of the most common and useful applications.
Keyboard Shortcut: Alt+. or Esc . inserts the last argument of the previous command. Press it multiple times to cycle through last arguments of earlier commands. Much more convenient than typing !$.

Example 8: Preventing Commands from Being Saved

# Method 1: Start command with space (if HISTCONTROL=ignorespace)
$ mysql -u root -p secretpassword # Note leading space
$ history | tail -2
523 history | tail -2
# The mysql command doesn't appear!

# Method 2: Set HISTFILE to /dev/null for current session
$ HISTFILE=/dev/null
$ ls /secret/dir
$ cat /secret/file
# These won't be saved to history file

# Method 3: Disable history for current session
$ set +o history
$ sensitive command 1
$ sensitive command 2
$ set -o history # Re-enable

# Method 4: Use HISTIGNORE
$ export HISTIGNORE="*password*:*secret*:*token*"
$ echo password123 # Won't be saved

# Method 5: Delete immediately after running
$ mysql -u root -p mypassword
$ history -d $(history 1 | awk '{print $1}')

# Method 6: Clear history before logging out
$ cat /dev/null > ~/.bash_history && history -c && exit
Explanation: There are multiple ways to prevent sensitive commands from being saved to history. Starting a command with a space (when HISTCONTROL=ignorespace) is the quickest method. Setting HISTFILE=/dev/null temporarily disables history saving for the current session. Using set +o history turns off history entirely until re-enabled. Adding patterns to HISTIGNORE filters out matching commands. For one-off sensitive commands, you can delete them immediately after execution. When working on sensitive systems, clearing history before logout is a good security practice.
Security Note: History files are readable by the user and potentially by system administrators. Never rely on history filtering as your only security measure. Don't type passwords on the command line if possible - use configuration files with restricted permissions, environment variables, or password prompts instead.

Example 9: History in Scripts and Loops

# Save history after every command (not just on exit)
# Add to ~/.bashrc:
PROMPT_COMMAND="history -a"

# Or more complex: append and reload to sync across terminals
PROMPT_COMMAND="history -a; history -c; history -r"

# Create a searchable archive of all commands
$ cat >> ~/.bashrc << 'EOF'
# Detailed history logging
export HISTTIMEFORMAT="%F %T "
export HISTSIZE=50000
export HISTFILESIZE=50000
shopt -s histappend

# Log all commands to a separate file with full details
PROMPT_COMMAND='if [ "$(id -u)" -ne 0 ]; then echo "$(date "+%Y-%m-%d %H:%M:%S") $(hostname) $(pwd) $(history 1)" >> ~/.logs/bash_history_detailed.log; fi'
EOF

# Search your detailed history
$ grep -i "apache" ~/.logs/bash_history_detailed.log

# Find commands run in specific directory
$ grep "/var/www" ~/.logs/bash_history_detailed.log

# Create command frequency report
$ history | awk '{CMD[$2]++;count++;}END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "% " a;}' | sort -nr | head -20
Explanation: The PROMPT_COMMAND variable specifies a command to run before each prompt. Setting it to history -a saves history after every command, not just on shell exit - critical for preserving history if the terminal crashes or system reboots. The more complex version (history -a; history -c; history -r) synchronizes history across multiple terminals by appending, clearing, and reloading. Creating a detailed log with timestamps, hostname, and working directory provides a comprehensive audit trail. The awk command analyzes which commands you use most frequently, helping you identify patterns and create useful aliases.
Advanced Logging: For security-critical systems, consider using a centralized logging solution or audit daemon (auditd) rather than just bash history. Bash history can be modified by users, while audit logs typically require root to modify and can be sent to remote systems.

Example 10: Sharing History Across Multiple Terminals

# Problem: Multiple terminals don't share history in real-time
# Terminal 1:
$ pwd
/home/craig
$ cd /var/log

# Terminal 2 (opened simultaneously):
$ history # Doesn't see "cd /var/log" from Terminal 1

# Solution 1: Manual sync when needed
# Terminal 2:
$ history -a # Append current session to file
$ history -c # Clear current session
$ history -r # Read from file
$ history # Now sees Terminal 1's commands

# Solution 2: Automatic sync (add to ~/.bashrc)
$ cat >> ~/.bashrc << 'EOF'
# Sync history across all terminals
export HISTCONTROL=ignoredups:erasedups
shopt -s histappend
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"
EOF

# Now all terminals see each other's commands in real-time

# Alternative: Use 'hstr' tool for better history management
$ sudo dnf install hstr # or apt install hstr
$ hstr --show-configuration >> ~/.bashrc
$ source ~/.bashrc
$ Ctrl+R # Now uses hstr interface

# Check current history settings
$ shopt -p | grep hist
shopt -s histappend
shopt -s cmdhist
$ echo $HISTSIZE
10000
Explanation: By default, bash history is per-session and only written to the file on exit, so multiple terminals don't share command history in real-time. This can be frustrating when working with multiple terminal windows. The manual solution uses history -a (append to file), history -c (clear session), and history -r (reload from file) to sync when needed. The automatic solution uses PROMPT_COMMAND to sync after every command - this ensures all terminals always have the most recent history but has a small performance cost. The erasedups setting removes duplicate commands throughout history, not just consecutive ones. Tools like hstr provide enhanced history management with better search interfaces.
Trade-off: Automatic history syncing ensures you never lose commands but can be confusing when commands from other terminals suddenly appear in your history. It also has a small performance impact. For most users, the default behavior with manual syncing when needed is sufficient.

Common Options

Option Description Example
-c Clear the history list (current session) history -c
-d offset Delete history entry at position offset history -d 523
-a Append new history entries to history file history -a
-n Read unread history lines from file history -n
-r Read history file and append to current history history -r
-w Write current history to history file history -w
-p args Perform history expansion on args and display result history -p !!
-s args Append args to history list as single entry history -s "fake command"

Keyboard Shortcuts for History

Shortcut Action Description
Ctrl+R Reverse search Search backward through history
Ctrl+S Forward search Search forward through history (needs stty -ixon)
Ctrl+P or Previous command Move back one command in history
Ctrl+N or Next command Move forward one command in history
Alt+. or Esc . Insert last argument Insert last argument of previous command
Alt+< Beginning of history Move to first command in history
Alt+> End of history Move to end of history (blank line)
Ctrl+O Execute and load next Execute current line, then fetch next from history

History Expansion Quick Reference

Expansion Meaning Example
!! Previous command sudo !!
!n Command number n !523
!-n n commands ago !-2
!string Most recent command starting with string !ssh
!?string Most recent command containing string !?apache
!$ Last argument of previous command vim !$
!^ First argument of previous command cat !^
!* All arguments of previous command ls !*
!:n Nth argument of previous command cd !:2
^old^new Replace old with new in last command ^http^https

Related Commands

Best Practices

1. Increase History Size

Default history size (500-1000) is too small. Increase to 10,000+:

export HISTSIZE=10000
export HISTFILESIZE=20000
2. Add Timestamps

Timestamps help with troubleshooting and auditing:

export HISTTIMEFORMAT="%F %T "
3. Prevent Duplicates

Keep history clean by ignoring duplicates:

export HISTCONTROL=ignoreboth
4. Save History Immediately

Don't wait for shell exit to save history:

PROMPT_COMMAND="history -a"
5. Master Ctrl+R

Interactive reverse search is faster than history | grep:

Press Ctrl+R, start typing, press Ctrl+R again for previous match

Security Considerations:
  • Never type passwords directly on command line
  • Use space-prefix for sensitive commands (with ignorespace)
  • Delete sensitive commands immediately: history -d N
  • Clear history before leaving shared/public systems
  • Consider setting HISTFILE=/dev/null for high-security sessions
  • Remember: root and admins can often read your history

Recommended ~/.bashrc Configuration

# Comprehensive history configuration

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

# Add timestamps
export HISTTIMEFORMAT="%F %T "

# Ignore duplicates and commands starting with space
export HISTCONTROL=ignoreboth

# Don't record some common commands
export HISTIGNORE="ls:ll:cd:pwd:exit:clear:history"

# Append to history file, don't overwrite
shopt -s histappend

# Save multi-line commands as one entry
shopt -s cmdhist

# Save history after each command
PROMPT_COMMAND="history -a"

# Enable Ctrl+S for forward search
stty -ixon

Exit Status

Code Meaning
0 Success
1 Failure - invalid option or history file access problem