133

We can use up and down arrow to navigate in command history.

In some IDEs, such as Matlab, if we input something and then press the arrow keys, we scroll among only the history commands starting with what we have input. That's really convenient, but in a shell terminal, this doesn't work.

Is there some way to gain a similar function in a shell terminal? And any other tips for improving efficiency in terminal use?

4
  • You could simply use a shell that provides such a feature, like fish ;)
    – yoann
    Commented Sep 23, 2015 at 23:13
  • @yoann you're assuming bash doesn't. It does, via readline, just not accessible by default.
    – muru
    Commented Sep 24, 2015 at 8:35
  • @muru I'm aware of CTRL+R in bash, and egmont's answer provides a neat way to do it with Page Up/Page Down. Is there however a way to do so with the arrow keys?
    – yoann
    Commented Sep 24, 2015 at 12:56
  • 1
    @yoann check out unix.stackexchange.com/a/76591/70524. Instead of \e[5~ and \e[6~, use \e[A, \e[B.
    – muru
    Commented Sep 24, 2015 at 13:02

9 Answers 9

173

What you are looking for is CtrlR.

Type CtrlR and then type part of the command you want. Bash will display the first matching command. Keep typing CtrlR and bash will cycle through previous matching commands.

To search backwards in the history, type CtrlS instead. (If CtrlS doesn't work that way for you, that likely means that you need to disable XON/XOFF flow control: to do that, run stty -ixon.)

This is documented under "Searching" in man bash.

1
  • 6
    Ctrl-Q to quit the frozen state, if you already hit Ctrl-S without turning off flow control first and got your terminal frozen.
    – HongboZhu
    Commented Jan 24, 2019 at 9:25
57

Place these in your ~/.inputrc:

"\e[5~": history-search-backward
"\e[6~": history-search-forward

These make Page Up and Page Down behave as you wish. (Some distributions have it already configured it for you.) I personally find these way more convenient than Ctrl+R or history.

Update: bash-5.2 / readline-8.2, released in Sep 2022, make these the default behavior. No more need to tamper with inputrc to set it up.

7
  • This is the most convenient way in all current answers. Could u plz give a little explanation on the working mechanism?
    – wsdzbm
    Commented Sep 24, 2015 at 8:43
  • 4
    ~/.inputrc or /etc/inputrc or the file referenced by the environment variable $INPUTRC is the line editing configuration file of all application using readline, including bash (your shell). It has certain built-in line editing capabilities, including these two: in bash's manual page search for one of these keywords to find out more. \e[5~/\e[6~ are the escape sequences generated by the Page Up/Down keys in most of the terminal emulators; to see it, launch the cat command and then press these keys (the escape byte is represented in the terminal as ^[, in inputrc as \e).
    – egmont
    Commented Sep 24, 2015 at 8:55
  • The example in your original question says that the Up / Down keys work this way in Matlab. It would be interesting to see what happened if you placed the sequence of Up and Down in inputrc and assign to this action; would it work correctly, or have nasty side effects as it conflicts with their default behavior. I don't know, I'd be happy to hear your findings if you experiment with this.
    – egmont
    Commented Sep 24, 2015 at 8:58
  • When I do echo $INPUTRC it is empty. I'm using Ubuntu 14.04
    – JorgeeFG
    Commented Sep 24, 2015 at 12:39
  • 7
    I personally prefer overriding up and down arrow to do this: "\e[A": history-search-backward and "\e[B": history-search-forward
    – A.Wan
    Commented Jun 7, 2018 at 23:32
14

Add the following lines to your ~/.inputrc

"\e[A": history-search-backward
"\e[B": history-search-forward

This is similar to egmont's answer, but instead of using Page Up and Page Down, it uses the escape sequences for Arrow Up and Arrow Down. This way is much more convenient to use on a Mac.

1
  • Run bind -f ~/.inputrc after creating the .inputrc file Commented May 19 at 11:14
14

Besides ^r / ^s history i-search:

alt. inserts the last "word" of the previous command at the cursor. Repeat it to get the last word from older commands. (But note that a trailing & counts as the last word for background commands).

This is super handy for mkdir foo, cd alt-dot. Even faster than up-arrow, ^a, alt-d (delete forward word), cd.

To get the 2nd-to-last word, use esc - 2 alt+. (i.e. use an emacs-style numeric argument to alt+.. Negative counts in from the end, positive counts forward from the start.) But this is usually more trouble than it's worth; at some point it's faster to reach for the mouse and copy/paste, or up-arrow and ^w / ^y part of it (see below).


If your terminal is set up nicely/properly, ctrl-left and ctrl-right will go backward/forward by words. If not, hopefully at least alt-b and alt-f will do the same thing.


ctrl-/ is an undo. You can use auto-repeat for deleting words much more efficiently if you can undo when you overshoot by a bit.


More powerful mixing/matching of commands comes from using the kill-ring, which works just like in Emacs. ctrl-y to paste the last ctrl-w / ctrl-u / ctrl-backspace / alt-d. alt-y to cycle through older killed text.

Multiple ctrl-w or whatever in a row make on kill-ring entry. Use left and right arrow or something to break up the entry if you want to remove two things and only paste one later.

Combining all of these together, you can

  • start typing a command
  • ctrl-r to go back to an old command and grab part of it with control-w or similar.
  • esc-r or alt+r to restore it to how it was before you deleted part of it.
  • alt-> to go to the end of history (i.e. down-arrow all the way), to get back to the command you were in the middle of.

Other interactive-use tips:

Enable shopt -s globstar, so you can do **/*.c (recursive including the current dir). Sometimes handy for interactive use, but usually find -name '*.c' -exec foo {} + is better.

If you write bash scripts, you'll find it handy to have shopt -s extglob enabled in your interactive shells, too. You will sometimes find a use for stuff like *.!(c|h) to match files that don't end with .c or .h.

Find aliases you like for ls -l, less, and anything else you do a lot. (cp -i, mv -i, and rm -I are nice. Don't get in the habit of depending on them to do a selective rm. GNU rm's -I asks once for all the args.)

I like alias m=less (m for "more"). I have less set up with , and . bound to previous / next file (lesskey). The default is a multi-keypress sequence that can't be used with autorepeat.


I like to do everything inside GNU screen. I find it easier to keep track of numbered screen-windows than a boatload of tabs in Konsole (or any other terminal emulator I've tried). If you don't already know screen, learn tmux because it's newer and less crufty.

To get something like the functionality of opening a new shell with the same cwd as another shell, I use a custom hook for cd/pushd/popd that lets me do cds 8 to cd to whatever dir my shell in screen window 8 is using. This works even for shells outside of the screen session, as long as there's only one screen session.

2
  • Mine doesn't seem to be "properly configured". A lot of the shortcuts I see here don't work, I am using stock Terminal from Ubuntu 14.04. How can I configure it?
    – JorgeeFG
    Commented Sep 24, 2015 at 12:47
  • @JorgeeFG: I think it worked for me out of the box with gnome-terminal in Ubuntu 14.04, before I switched to KDE. The relevant option is in your terminal settings, esc-prefix vs high-bit, and maybe some other settings. Some of them don't work perfectly for me through ssh. (e.g. ctrl left/right munge the escape-code for the arrow key, and I get 5D appearing literally) Commented Sep 24, 2015 at 17:38
10

The means I usually use is to combine the history command with grep

IE:

history | grep <command im looking for>

That will display a numbered history of commands you have typed that contain that command, you can then use:

!<number listed in history command>

to redo that command.

IE:

history | grep history

142  history
143  history | grep lvresize
568  history | grep echo
570  history | grep echo
571  history | grep history

followed by: !571

will repeat history | grep history

8
  • 1
    C-R = much better + much safer Commented Sep 23, 2015 at 17:16
  • 1
    Perhaps, Personally I find a history piped to grep to be a faster means of finding most commands. As far as Safer, I'm not sure what you mean, what are the inherent risks in using history as apposed to searching through it with c-R?
    – Gravy
    Commented Sep 23, 2015 at 17:25
  • 2
    @Gravy I suspect PSkocik means the ! history substitution is less safe.
    – derobert
    Commented Sep 23, 2015 at 17:27
  • 3
    @Gravy The inherent risks would be accidentally getting the wrong line. No idea why your terminal has frozen, unless you used Control-S and you have xon/xoff flow control enabled (often the default). If so, Control-Q will bring it back.
    – derobert
    Commented Sep 23, 2015 at 17:36
  • 1
    I agree with @PSkocik, c-r is much better because it's easier to edit the history line, rather than just run it again the same way. Running the exact-same command again is a trivial case of what you can do to save time re-typing variations on complex one-liners, or tab-completing a different file in a long path. See my answer. Commented Sep 23, 2015 at 22:06
5

I always tend to configure my machines with an large HISTSIZE value so it keeps a longer history list, as well as HISTTIMEFORMAT with the time stamp value so I can see when was the command ran.

export HISTSIZE=10000
export HISTTIMEFORMAT="%m/%d/%Y %T "
3

I used daily these tips (and some others) in my bash terminal:

  • Execute last command: !!

  • Print last command: !!:p (It's equal to press up arrow [])

  • Execute command N from history: !N

  • Print command N from history: !N:p

  • Execute last command starting with prefix from history: !prefix

  • Print last command starting with prefix from history: !prefix:p

1
  • 1
    I think that using the command N from history is one of the greatest ever paths for shoot oneself in the foot for most humans :-) Just saying
    – matanox
    Commented Mar 20, 2020 at 15:45
2

If it's okay for you to use zsh instead of bash, you can use oh-mi-zsh for that.

You can navigate your command history with the up and down arrows. It also allows the same navigation when you have already typed the text (as in Mathlab).

edit: Oh-my-zsh is a large, developer-oriented software package that includes many other features, e.g. aliases, themes, plugins. These extras make the distribution more complex to use than a keyboard shortcut.

https://github.com/robbyrussell/oh-my-zsh

0
1

Add the following alias to ~/.bashrc

alias h='history | awk '"'"'{$1="";print}'"'"' |sed "s/^ *//" |grep -v "^h " | sort | uniq | grep'

Usage: h fire will get me a list of commands contain fire. or h ^fire will get me a list of commands begin with fire.

This is useful when I want to view a series of commands at the same time.

By the way, '"'"' is ugly but I couldn't find other ways to avoid single quotes in single quotes.

2
  • fyi -h="history | awk '{\$1=\"\"; print}' should work. alternatively create a function and call that.
    – user14755
    Commented Jun 17, 2016 at 1:37
  • thank you DarkHeart, but I tried your code, found not worked in my environment, maybe there is something different in mine Commented Jun 17, 2016 at 3:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .