Finding characters on a command line with bash

From: http://tiswww.case.edu/php/chet/readline/readline.html#IDX172    Thanks to Chet Ramey for this.

character-search (C-])
A character is read and point is moved to the next occurrence of that character. A negative count searches for previous occurrences.


Say you have the command line:
grep -ri --color isinstance *

and you want to move to the beginning of the line and the the second r.

Here's a method:
    1. Press Control-A (to bring your cursor to the beginning of the line)
    2. If you like to count, press ESCAPE then 2 to indicate the second match.
    3. Press Control-] and then r to indicate the character you want to search for.
Or  if you don't like to count:
    1. Press Control-A (to bring your cursor to the beginning of the line)
    2. Press Control-] and then r to indicate the character you want to search for, and the cursor will advance to the first r.
    3. Again, press Control-] and then r to indicate the character you want to search for, and the cursor will advance to the second r.
This all assumes that bash is set to emacs mode (it tends to be by default).  You can set bash to emacs mode by typing

set -o emacs

To set bash to vi mode by instead

set -o vi

Say you have the command line:
grep -ri --color isinstance *

and you want to move to the beginning of the line and the the second r, but in vi mode!

Here is the vi method: 
    1. Press 0 (that's a zero, to bring your cursor to the beginning of the line)
    2. Press f (for find) and then r to indicate the character you want to search for, and the cursor will move to the first r.
    3. Press (that is a semicolon) to repeat the search and move to the next r.
Or  if you want to repeat things:
    1. Press Control-A (to bring your cursor to the beginning of the line)
    2. Press f (for find)  and then r to indicate the character you want to search for, and the cursor will advance to the first r.
    3. Again, press f and then r to indicate the character you want to search for, and the cursor will advance to the second r.






Searching backwards for characters on the command line


character-search-backward (M-C-])
A character is read and point is moved to the previous occurrence of that character. A negative count searches for subsequent occurrences.


Basically this is the same as the character-forward-search, but if you are working on an ssh session or don't have a magic META key set up, you can replace the M (which means press the META key) with an ESCAPE character.

So for emacs mode:

  1. Press Control-E (to get to the end of the line).
  2. Press ESCAPE then Control-] and finally the character you want to search backwards for.
To search backwards three times for r, that is the third r from the end of the line, type:

ESCAPE 3 ESCAPE Control-] r

This is the same example in vi mode:

  1.  Press $ to get to the end of the line
  2. Press f (to find forward) and the character r 
    As you are at the end of the line, no 
    is to be found forward so no cursor motion happens
  3. Press  and ,  (that is a comma).  This will search backwards three times for a comma.
    (Or instead press the comma three times and watch the cursor move).
Handy vi trick: Press comma and semicolon to flip backwards and forwards across the previous and current matching characters.


Note: The emacs Control-] didn't work on bash v1.14 but that was from the 1990's :-)


Commenting out the current command line

If you find that you are unhappy with the command line, a good way to leave it and come back later is to comment out the whole line. The commented line will stay in the command history for later perusing or editing :-)

In emacs mode:  Press ESCAPE and # and a comment character will appear at the beginning of  the line and you will advance to a new, empty line.

In vi mode: Press # and a comment character will appear at the beginning of command line and you will advance to a new, empty line.


vi or emacs mode: Which am I in?


lent@sample:~$ set -o |grep -E ^vi\|ema
emacs off
vi on
lent@sample~$ # This would be in vi mode :-)



Switching quickly from emacs to vi mode and back.

emacs-editing-mode (C-e)
When in vi command mode, this causes a switch to emacs editing mode.   

So in vi mode press Control-E to return to emacs mode.


vi-editing-mode (M-C-j) 
When in emacs editing mode, this causes a switch to vi editing mode.

So in emacs mode press ESCAPE Control-J to switch to vi mode


Sadly, these key bindings are not universal.  To check yours, type:

 bind -p |grep -editing-mode
# emacs-editing-mode (not bound)
# vi-editing-mode (not bound)

 bind -V
bind-tty-special-chars is set to `on'
blink-matching-paren is set to `on'
byte-oriented is set to `off'
completion-ignore-case is set to `off'
[... more stuff ...]
comment-begin is set to `#'
completion-query-items is set to `100'
editing-mode is set to `emacs'
keymap is set to `emacs'

The binding can be done permanently in a GNU readline ( via  $INPUTRC, ~/.inputrc, or /etc/inputrc)  or bash initialization file (via ~/.bashrc or /etc/bash.bashrc ).

Here is how to set the switching commands to ESCAPE v (that is the escape key followed by the lowercase v key) and ESCAPE e .
As a note,  this is really META-v and META-e,  so if you are using a Linux console or a terminal emulator like putty, your might be able to type just ALT-v and ALT-e as well.

set -o vi; bind '"\M-e": emacs-editing-mode'; bind '"\M-v": vi-editing-mode'
set -o emacs; bind '"\M-e": emacs-editing-mode'; bind '"\M-v": vi-editing-mode';


Emacs and vi mode seem to have their own separate key bindings.

Thinking about it, having vi and emacs mode have different mappings of keys to functions does make a good bit of sense,
but I didn't think of it when I wanted magic ALT-e and ALT-v keys to switch to emacs and vi modes :-)

Here's a little session that shows the modes.

lent@sample:~$ # Let us check the current mode
lent@sample:~$ set -o |grep -E ^vi\|emacs
emacs on
vi off
lent@sample:~$ # Are the mode switching functions bound to keyboard keys?
lent@sample:~$ bind -p |grep editing
# emacs-editing-mode (not bound)
# vi-editing-mode (not bound)
lent@sample:~$ # How about in vi mode?
lent@sample:~$ set -o vi
lent@sample:~$ # Did we make it to vi mode?
lent@sample:~$ set -o |grep -E ^vi\|emacs
emacs off
vi on
lent@sample:~$ # Yup! What is bound here?
lent@sample:~$ bind -p |grep editing
# emacs-editing-mode (not bound)
# vi-editing-mode (not bound)
lent@sample:~$ # Okay nothing is bound in either mode. Let us set the keys for this session.
lent@sample:~$ set -o vi; bind '"\M-e": emacs-editing-mode'; bind '"\M-v": vi-editing-mode';bind -p |grep editing
"\M-e": emacs-editing-mode
"\M-v": vi-editing-mode
lent@sample:~$ set -o emacs; bind -p |grep editing
# emacs-editing-mode (not bound)
# vi-editing-mode (not bound)
lent@sample:~$ # Aha, they are separate! Let us bind the emacs side too!
lent@sample:~$ set -o emacs; bind '"\M-e": emacs-editing-mode'; bind '"\M-v": vi-editing-mode'; bind -p |grep editing
"\M-e": emacs-editing-mode
"\M-v": vi-editing-mode
lent@sample:~$ set -o vi ;bind -p |grep editing
"\M-e": emacs-editing-mode
"\M-v": vi-editing-mode
lent@sample:~$ set -o |grep -E ^vi\|ema
emacs off
vi on
lent@sample:~$
#Pressed ESCAPE then e . So what is our mode now?
lent@sample:~$ set -o |grep -E ^vi\|ema
emacs on
vi off
lent@sample:~$
#Yeah! we switched! Are our keys still bound?
lent@sample:~$ bind -p |grep editing
"\M-e": emacs-editing-mode
"\M-v": vi-editing-mode
lent@sample:~$ #Pressed ESCAPE then v. So what is our mode now?
lent@sample:~$ set -o |grep -E ^vi\|ema
emacs off
vi on
lent@sample:~$ bind -p |grep editing
"\M-e": emacs-editing-mode
"\M-v": vi-editing-mode
lent@sample:~$

Comments