Can I search history in bash and run the result?
Type Ctrl R at the command line and start typing the previous command. Once a result appears keep hitting Ctrl R to see other matches. When the command you want appears, simply press Enter
Note that while Ctrl R is the default, if you wanted the command (
reverse-search-history) to be bound to Ctrl T you could configure that with the following:
bind '"\C-t": reverse-search-history'
There are a whole host of other readline bindable commands that are available to you as well. Take a look at the
bash man page.
Bash has many facilities to search and access interactive command history. The most basic of which is the
history builtin. Typing just:
Will print a list of commands along with a numeric index, like:
$ history 1 clear 2 ls -al 3 vim ~/somefile.txt 4 history $
You can then execute any of these commands using their numeric index by prefacing the index with a single
!, as Mitch pointed out:
Will execute the
clear command. The history builtin has many features itself, you can see more in the
history man pages.
You can also specify relative negative offsets when using the
! designator, so using our history list above, if we wanted to execute
vim again, we could do:
Which is basically telling bash to execute the command you ran "two commands ago." To run the previous command in the history list, we can just use
!! (which is just shorthand for
! designator doesn't limit you to numerically specifying which command to run. hayalci showed that you can instruct
bash to execute a command based on either the text it begins with (using
!) or text within the command itself (using
!?). Again, using our example history list above, if we wanted to execute
clear again, all we need to do is type:
and press Enter. And what about
vim? That is as simple as:
The most important point from hayalci's response is the call to the
$ shopt -s histverify
This will enable history verification so that commands that are matched by the
!? designators are not blindly executed, but instead filled in on the command line so you can ensure they will do no evil before executing them. This is even more important when you are executing commands as the root user. This option can be set in your
.bashrc startup file so that it is set whenever you log in.
As an alternative to crtl+R, you can search history by typing
This will search the history for the most recent command beginning with 'text'.
But I suggest you put this in your .bashrc to prevent execution of wrong command.
shopt -s histverify
This instructs bash such that, after any history actions (like
!!:s/prev_text/after_text), it places the resulting line to the command prompt. Then you can review or edit the command, and press Enter afterwards.
I prefer to use history-search-backward over reverse-search-history. The former lets you type a few characters of the command then press the search key, as opposed to hitting the search key first then typing the search string.
By default on my system, M-p and M-n bind to similar functions but I prefer binding the arrow keys:
bind '"\e[A":history-search-backward' bind '"\e[B":history-search-forward'
Excellent writeup, Sean! I'd put this in a comment, but I'm a few reputation points shy. :-)
Another related and useful technique is the ability to run a previous command while changing a word. Say you typoed the directory name, or want to change the file name:
$ echo my name is bob my name is bob $ ^bob^jordan echo my name is jordan my name is jordan
Notice that the command is expanded, replaced, and output before the command is run, so if the wrong command is run you can see what bash thought it was doing.
As navigation through history using Ctrl-r is IMO cumbersome, you may want to consider hh:
which makes navigation much simpler, straightforward and efficient - including running the command:
CTRL+R works just fine, like @John1024 suggested, but is somewhat tedious if many of your recent commands are similar and you want a quick way to scan them all. An alternative would be to use
$ history | grep keyword
I like HSTR but I can't seem to be able to install it sometimes.
So I wrote an alias using fzf which mimics its behavior (
hx, for "history execute")
alias hx='eval $(history | sed "s/^ *[0-9]* *//g" | fzf --tac --tiebreak=index --height=10)'
history: well, get the history
sed: remove the number column from the list (POSIX)
fzf: here is the magic, allows you to fuzzy-search the list interactively, or move with
C-K, then execute a command with
--height: set the numbers of lines shown.
--tac: revert list (more logical for an history)
--tiebreak=index: keep the history order when fzf updates the results