The bash command history shows the previously used commands. By default, the history is saved in memory per session and can be saved to a file for later sessions. We will explore ways to show, search and modify the history in this blog post. I use RHEL and Debian-based Linux distributions and bash in this blog post as a reference. # Configuration # I want to start with ways to configure the behavior of the bash history. The configuration of the history can be changed in the bash startup file. Those can typically be found in the home directory of the user. System-wide `/etc/profile` or in the home directory `~/.bashrc` or `~/.profile`. There are more, but just to list some examples. If you want to use an option for one session only, you can just type it in like this: `HISTFILE=/dev/null` or `unset HISTFILE` In both ways, you would disable the history for the current bash session. # The basics # The bash history should be enabled by default, but you might want to change some settings. The history file that is stored on disk can be found with the following command: : `echo $HISTFILE` The default location for the history on disk is `~/.bash_history`. Add the following option to change the name and storage location of the history file on disk: : `HISTFILE=/path/to/the/history.txt` Show the complete history from memory: : `history` Just show the last number of commands: : `history 20` Read history from disk to memory: : `history -r` Append history entries from memory to disk: : `history -a` Overwrite the disk history with the memory history: : `history -w` Since I am used to working with multiple sessions and I want to share the history of them, I've added the following line to my startup file to append every entry to the history on disk. `export PROMPT_COMMAND='history -a'` Delete a specific history entry or range: : `history -d 20` *# one specific entry* : `history -d 15-20` *# range* : `history -d -5` *# last 'n' of entries* #### Disabling bash command history # As mentioned above, there are multiple options to disable the bash command history. `HISTFILE=/dev/null` or `unset HISTFILE` #### Number of history entries The following option sets the number of entries that are displayed if you enter `history`: : `HISTSIZE=20` The following option sets the maximum number of entries in the history on disk: : `HISTFILESIZE=2000` # Search function # You can start a **reversed search** through the history by pressing `CTRL` + `r` and entering the search term. You can jump to the next result by pressing `CTRL` + `r` again. After finding the desired command, you can press `TAB` to get filled to the current command line or press `ENTER` to run the command immediately. If you skipped through your desired command, you can cancel the current search request with `CTRL` + `g` and start from the top again. There is no native way to jump forward again - but you could add a forward search by adding `stty -ixon` to your startup file. The keyboard shortcut for the forward search is `CTRL` + `s`. #### Using 'grep' I prefer to use grep to find commands. Simply use one of these examples to do so. ```bash history | grep SEARCHTERM or grep SEARCHTERM $HISTFILE ``` **Side note**: use the `-i` flag if you want search case-insentitive. #### Add comments to commands You can add comments to commands with `#`. This makes it easy to find commands again or document the thoughts behind the command in troubleshooting sessions and later reviews. ```bash kuser@pleasejustwork:$ echo nightmare # dolphins chasing me in a mall nightmare ``` # Exclusions # We can add exclusion with the `HISTIGNORE` option in your startup file. This can be useful for privacy and security reasons. There are some predefined options we can choose from: : `ignorespaces` - if the command starts with a `SPACE`, it will be excluded : `ignoredups` - duplicate commands will be excluded : `ignoreboth` - both above-mentioned options together If those options are not enough, you can create your own rules. For example, the `ignoreboth` rule could be written like this: `HISTIGNORE="&:[ ]*"` *# the ampersand `&` means no duplicates, `:` is the separator, `[ ]*` checks if the command begins with a `SPACE`* You can add commands too. `HISTIGNORE="ls:pwd:cd"` # Timestamps # Timestamps are often important for reviews of troubleshooting sessions. With the `HISTTIMEFORMAT` option, you can add timestamps in various formats to your history. The default history looks like this: ```bash kuser@pleasejustwork:$ history 6 1150 history 1151 vim .bash_history 1152 vim .bashrc 1153 source .bashrc 1154 ls 1155 history ``` And the same lines look like this after adding `HISTTIMEFORMAT="%F %T "` to the configuration: ```bash kuser@pleasejustwork:$ history 6 1150 02/02/23 18:03:32 history 1151 02/02/23 18:03:45 vim .bash_history 1152 02/02/23 18:05:03 vim .bashrc 1153 02/02/23 18:05:22 source .bashrc 1154 02/02/23 18:05:26 ls 1155 02/02/23 18:05:30 history ``` You can adjust the format with the following placeholders: ```bash %d: day %m: month %y: year %H: hour %M: minutes %S: seconds %F: full date (Y-M-D format) %T: time (H:M:S format) %c: complete date and timestamp (day-D-M-Y H:M:S format) ``` # Re-run commands # `!!` is a variable for the previous command and, for example, can be used to run the last command as 'sudo' . ```bash kuser@pleasejustwork:$ whoami kuser kuser@pleasejustwork:$ sudo !! [sudo] password for kuser: root ``` --- `!` can be used to re-run the last command starting with a chosen term. ```bash kuser@pleasejustwork:$ history 5 41 ping ittavern.com # !ping 42 whoami # !whoami 43 nmap -sP 10.10.10.0/24 # !nmap 44 vim .bashrc # !vim 45 history kuser@pleasejustwork:$ !who # runs immediately and auto-completes kuser ``` --- `!n` would run the 'n' command in the history, and `!-n` refers to the current command minus 'n' ```bash kuser@pleasejustwork:$ history 5 41 ping ittavern.com # !41 / !-5 42 whoami # !42 / !-4 43 nmap -sP 10.10.10.0/24 # !43 / !-3 44 vim .bashrc # !44 / !-2 45 history # !45 / !-1 / !! kuser@pleasejustwork:$ !-4 # runs immediately kuser ``` #### modify and re-run previous command With the following syntax, you can replace keywords from the previous command and run it again. `^OLD KEY WORD^NEW KEY WORD OR PHRASE^` **Example:** ```bash kuser@pleasejustwork:$ sudo nmap -T3 10.10.22.0/24 -p 80,443 kuser@pleasejustwork:$ ^22^50^ # the command will be executed immediately kuser@pleasejustwork:$ sudo nmap -T3 10.10.50.0/24 -p 80,443` ``` Use a backslash `\` as an escape character if you need to find or replace a `^`. --- {{% contact %}} --- **More reading:** {{% post-list tags=linux stop=5 %}}{{% /post-list %}} {{% post-list stop=5 %}}{{% /post-list %}}