Most of us know about using the bang operator (`!`) to recall an entry from our bash history:
$ ! # repeat last command
$ !22 # repeat command 22
You can use “
!:” followed by a number to substitute in arguments from previous commands. So, for example, to run the command “dosomething” on the first argument of the previous command:
$ dosomething !:1
fc command is also very useful, opening up the default editor to let you edit previous commands. Saving and exiting will execute the command, while canceling the save (e.g., “
:cq” in Vim) will abort.
$ fc # "fix" previous command
$ fc -10 0 # "fix" previous 10 commands
Things get really slick when using the `CTRL-R` and `CTRL-S` operations. These will incrementally match a string against entries in your shell history.
For example, in my shell, typing `CTRL-R` followed by “mak” yields:
(reverse-i-search)`mak': make PREFIX=~/Documents/System/Environment/local/ install
While typing `CTRL-R` followed by “Pro” yields:
(reverse-i-search)`Pro': cd Documents/Projects/Miscellaneous/msbayes-ext/
From here, I can use `CTRL-R` or `CTRL-S` to scroll backward or forward through all possible matches. I can accept and execute the match by hitting `ENTER`, or accept the match but not execute it by hitting `ESC` (thus allowing me to edit the line). Hitting `CTRL-C` or `CTRL-G` aborts and returns me to the regular interactive shell.
This incremental history search is fantastic! No more “
history | grep something” followed by cutting-and-pasting and then editing. But often I have already started typing something, and then decide that I want to complete this from some entry in my history. In these cases, `CTRL-R` and `CTRL-S` will not be as efficient, as invoking them will result in me having to re-type the partially entered command. However, a few lines added to my “
~/.bashrc” sets Bash’s readline options to allow my to call up completion based on incremental matching of my partial command against my shell’s history:
# Ctrl-p: search in previous history
bind 'Control-p: history-search-backward'
bind -m vi-insert 'Control-p: history-search-backward'
bind -m vi-command 'Control-p: history-search-backward'
# Ctrl-n: search in next history
bind 'Control-n: history-search-forward'
bind -m vi-insert 'Control-n: history-search-forward'
bind -m vi-command 'Control-n: history-search-forward'
The above settings are so as to get this behavior in both Vi-mode readline (my default) as well as Emacs-mode readline (readline’s default).
Incidentally, while not history-editing specific, if you do not already know about the `v` or `CTRL-X CTRL-E` commands, you really should check them out. The former works in Vi-mode, while the latter works in Emacs-mode. Both of them open up the current command for editing in your default editor. In combination with the history search/completion options described above, it makes for a really potent and efficient Bash session: you can call up a previous command using `CTRL-R`/`CTRL-N`, hit `ESC` and then `v` or `CTRL-X CTRL-E` to open up the default text editor and tweak the line using the full power and sophistication afforded by the editor. Then, simply save and exit (e.g., “
:wq“) to execute, or cancel (e.g., “
:cq“) to abort. I use Vi-mode readline, and I have mapped `CTRL-V` to be able to call up Vim on my command when I am insert mode by adding the following lines to my “
# Ctrl-v: (insert mode) switch to command mode and edit in vi
bind '"\C-v": "\ev"'