11

Control-R, my favorite Unix shell command

If you use a modern, open-source Unix shell — and by that, I basically mean either bash or zsh — then you really should know this shortcut.  Control-R is probably the shell command (or keystroke, to be technical about it) that I use most often, since it lets me search through my command history.

Let’s start with the basics: When you use bash or zsh, your commands are saved into a history, typically put in the environment variable HISTFILE.  I use zsh (thanks to oh-my-zsh), and it puts my HISTFILE in ~/.zsh_history.  How many commands does it store?  That depends on the value of the environment variable HISTSIZE, which in my case is 10,000.  Yes, I store the 10,000 last commands that I entered into my shell.

Now, before control-R, there were a bunch of ways to search through and use the history.  Each command has its own number, and thus if you want to replay command 5329, you can do so by typing

!5329

But this requires that you keep track of the numbers, and while I used to do that, I found it to be more annoying than useful.  What I really wanted was just to repeat a command … you know, the last time I ssh’ed into a server, or something.  So yeah, you can do

!?ssh

and you’ll get the most recent “ssh” command that you entered.  But what if you have used ssh lots of times, to lots of servers?  You could start to search for the server name, but then things start to get complicated, messy, and annoying.

What control-R does is search backwards through HISTFILE, looking for a match for what you have entered until now.  If you use Emacs, then this will make perfect sense to you, since control-R is the reverse version of control-S in Emacs.  If you don’t know Emacs, then it’s a crying shame — but I’ll still be your friend, don’t worry.

Let’s say you have ssh’ed into five different servers today, and you want to ssh again into the third server of the bunch.  You type control-R, which puts you into bck-i-search (i.e., “backward incremental search”) mode.  Now type “s” (without enter).  The most recent command that you entered, which contains an “s”, will appear.  Now type another “s” (again, without pressing enter).  The most recent command containing two “s” characters in a row will appear.  Depending on your shell and configuration, the matching text might even be highlighted.

Now enter “h”.   In my case, I got to the most recent call to “ssh” that I made in my shell.  But I don’t want this last (fifth) one; I want the third one.  So I enter control-R again, and then again.  Now I’m at the third time (out of five) that I used ssh today, at the command I want.  I press “enter”, and I’ve now executed the command.

While searching backward, if you miss something because you hit control-R one too many times, you can use control-S to search forward.  You can use the “delete” key to remove characters, one at a time, from the search string.  And you can use “enter”, as described above, to end the search.  I should also note that I’ve modified my zsh prompts such that the matched text in control-R is highlighted, which has made it even more useful to me.

So, when was the last time I entered the full “ssh” command into a client’s server? I dunno, but it was a while ago… since the odds are that within the 10,000 most recent commands, I’ve got a mention of that client’s server.  And if I needed to pass specific options to ssh, such as a port number or a certificate file to get into AWS, that’ll be in the history, too.  By combining a huge history with control-R, you can basically write each command once, and then refer back to it many times.

Now the fact is that control-R isn’t really part of bash or zsh, per se.  Rather, it’s part of a GNU library called “readline” that is used in a large number of programs.  For example, it’s used in IPython, Pry, and the psql command-line client for PostgreSQL.  Everywhere I go, I can use control-R — and I do!  Each program saves its own history, so there’s no danger of mixing shell commands with PostgreSQL queries.

 

Click Here to Leave a Comment Below 11 comments
maybe - 5 years ago

I’m a big fan of reverse-search-history too. So much so that I miss it in the Firefox console.

I also sometimes add tagging comments to hard-earned commands, e.g.


git log --perl-regexp --grep="\b(?i:FIX).*\d+" # ignore case

Here are some of my additional settings from .bashrc, which help me avoid losing history, etc.


# don't put duplicate lines in the history. See bash(1) for more options
export HISTCONTROL=ignoredups
# ... and ignore same sucessive entries.
export HISTCONTROL=ignoreboth
export HISTTIMEFORMAT='%Y%m%dT%H%M%S%z '
# Free up forward-search-history (C-s) in bash.
stty stop ^J
# Append to the history file instead of overwriting.
shopt -s histappend
# Append unsaved commands to history file.
PROMPT_COMMAND="history -a;$PROMPT_COMMAND"

Reply
Ian Taylor - 5 years ago

Awesome, I didn’t know about this command!

Also with oh-my-zsh you can type part of the command and hit the up or down arrow to search through the history, without having the go into control-r, this is extremely useful. I find myself hardly ever typing full
commands now, I just type “ssh” and hit the up arrow to find the connection I want (if I have typed it before of course).

Reply
Stephen - 5 years ago

Cool article! Thanks for sharing this, not only did I learn about Control-R/S which are very useful, but I didn’t know that I could modify the size of my Bash history!

Reply
William Riley-Land - 5 years ago

^R is definitely one of the handiest things in bash. maybe’s comment is quite eye opening … *goes off to study more custom configuration for bash*

Reply
    luca - 5 years ago

    CTRL+R is wonderful, but it’is better to keep a separated bash ethernal history, just in case:

    export HISTTIMEFORMAT=”%h/%d/%y – %H:%M:%S ”
    export HISTCONTROL=ignoreboth
    export HISTSIZE=5000
    shopt -s histappend
    PROMPT_COMMAND=”${PROMPT_COMMAND:+$PROMPT_COMMAND ; }”‘echo $$ $USER “$(history 1)” >> ~/.bash_eternal_history’

    Reply
Ed - 5 years ago

Great article..
I do not know Emacs, but I do know vi, and one can use VI to do this also.

To enable vi mode:
set -o vi

Then, to search backwards:
?ssh

use the n for next till you find the one you want.

Reply
Pedro - 5 years ago

$ cat .inputrc

“\e[A”: history-search-backward
“\e[B”: history-search-forward

Something way better than Ctrl + R. Simply add those lines to your ~/.inputrc, restart your shell, then type the first few letters of some command and navigate up and down within your filtered history now. Try it. You will never use Ctrl + R. Ever again.

Reply
Mike - 5 years ago

Even easier is to have PageUp and PageDown mapped in your /etc/inputrc to do the history reverse search. On Ubuntu, these are set up but commented out by default. Here’s what the lines in /etc/inputrc should look like:

# alternate mappings for “page up” and “page down” to search the history
“\e[5~”: history-search-backward
“\e[6~”: history-search-forward

From memory, I think Fedora and derivatives have these uncommented already. So no need to hit ctrl-r, just type the first few characters of the command you want, then PageUp to recall it.

Reply
Maldito Nerd - 5 years ago

I use this one, does exactly the same but more much more quickly. Uncomment this two lines in your /etc/inputrc file:

# alternate mappings for “page up” and “page down” to search the history
“\e[5~”: history-search-backward
“\e[6~”: history-search-forward

There you have, a FAR more better method to accomplish that. Source the file or logout and login again. Now you can search and reverse search any command in your .bash_history by just typing one or two chars and pressing page-up/page-down.

Cheers!

Reply
hork - 5 years ago

Be warned that pressing CTRL-S in PuTTY will send XOFF (pause transmission) and on some systems your terminal will apparently freeze. Press CTRL-Q for XON .(resume transmission).

Reply
Kelas - 5 years ago

For 99% of actual use cases in the past 15 years, a simple bang (plus up/down arrow keys) covers most of my reverse-history needs. That is:

$ !prefix

The more “advanced” your command line heroics will get, the faster the day will come when you will destroy a system with a wrong history item.

Reply

Leave a Reply: