95

I've been meaning to find a solution for this for YEARS.

I am sooo much more productive in vim when manipulating files than bash for this reason.

If I have

file_12390983421
file_12391983421
file_12340983421
file_12390986421

In bash and type file_1->tab , it obviously lists:

file_12390983421 file_12391983421 file_12340983421 file_12390986421

And this is horrible and painful to work with.

The same sequence in vim will loop through the files one at a time.

Please someone tell me how to do this in bash, or if there is another shell that can do this, I'll switch tomorrow.

pixelearth
  • 13,674
  • 10
  • 62
  • 110

5 Answers5

97

By default TAB is bound to the complete readline command. Your desired behavior would be menu-complete instead. You can change your readlines settings by editing ~/.inputrc. To rebind TAB, add this line:

TAB: menu-complete

For more details see the READLINE section in man bash.

sth
  • 222,467
  • 53
  • 283
  • 367
  • 1
    This works perfectly. One thing, is there a way to get this to go backwards? In vim I use shift+tab, and if I accidentally go to far, I just go back, or if I want to start at the end of the list. Something I do all day long in vim... but doesn't seem to work with menu-complete. – pixelearth Aug 25 '11 at 04:41
  • 9
    menu-complete will auto replace you input, but will not display a candidate list. Is there a way to do both? – Leon Aug 25 '11 at 07:22
  • 19
    @pixelearth: There is also `menu-complete-backward`, and at least on my terminal Shift-Tab seems to send the `\e[Z` escape sequence. This gives you this .inputrc entry: `"\e[Z": menu-complete-backward` – sth Aug 25 '11 at 10:58
  • @sth Hm. I don't seem to have menu-complete-backward: GNU Readline 6.1 Snow Leopard – pixelearth Aug 27 '11 at 04:54
  • 2
    It'd be really cool if you could cycle through the possibilities AND see the list of possibilities, like in vim. It's a pain to cycle through every possible file name in a directory just to find out what's in there when completing a command. – James M. Lay Jan 08 '15 at 07:54
  • 6
    Not sure if that is still relevant, but I had the same problem as James M. Lay and solved it by putting `Tab:complete "\e[Z":menu-complete` in my `.inputrc`. That way, `Tab` has the original behavior and `Shift` + `Tab` lets you cycle through suggestions. Edit: There's supposed to be a line break after `Tab:complete`. I can't properly style that here in the comments. – karpfen Dec 21 '16 at 10:18
  • 1
    You may want to specify that the command to be put in `.bashrc` is `bind TAB:menu-complete`. – Claudio Jan 10 '17 at 13:46
  • @Claudio What is the difference between putting that bind in `.bashrc' versus putting the line in `.inputrc` as the answer suggests? – Jonathan Hartley Oct 04 '19 at 16:45
65

For bash >= 4 you might like these settings. You can try them directly on the command-line, and put them in your ~/.bash_profile if you like them.

# If there are multiple matches for completion, Tab should cycle through them
bind 'TAB:menu-complete'
# And Shift-Tab should cycle backwards
bind '"\e[Z": menu-complete-backward'

# Display a list of the matching files
bind "set show-all-if-ambiguous on"

# Perform partial (common) completion on the first Tab press, only start
# cycling full results on the second Tab press (from bash version 5)
bind "set menu-complete-display-prefix on"

This setup is similar to Vim's set wildmode=longest:full:list,full

I pulled these settings from this question on the Unix & Linux site.


By the way, since you are here, here are some other great bindings:

# Cycle through history based on characters already typed on the line
bind '"\e[A":history-search-backward'
bind '"\e[B":history-search-forward'

# Keep Ctrl-Left and Ctrl-Right working when the above are used
bind '"\e[1;5C":forward-word'
bind '"\e[1;5D":backward-word'

This means if you type ssh<Up> it will cycle through previous lines where you ran ssh

If you don't like what you got, you can clear the line with Ctrl-K Ctrl-U

I pulled these settings from this question on AskUbuntu.

joeytwiddle
  • 29,306
  • 13
  • 121
  • 110
  • 2
    If you are using Mac OS X then check your `bash --version`. My Mac has only bash version 3, which unfortunately means the last two binds will have no effect. – joeytwiddle Oct 27 '18 at 05:36
  • 2
    I have an answer for getting the latest `bash` (currently 5.0.2) on macOS at https://stackoverflow.com/a/55011144/117471 – Bruno Bronosky Mar 05 '19 at 20:37
  • 2
    This config needs to be in .bashrc (some other answer mentions .inputrc). – Étienne Jul 10 '19 at 12:27
  • Note that turning on show-all-if-ambiguous will not allow menu-complete if it's ambiguous (which might or might not be useful), unless it's bound to some other keys. // also, to figure out the key code sent press before the key. – user202729 Dec 27 '20 at 14:14
  • @Étienne `.bashrc` seems to be good for aliases. However binds throw up an error when using rsync ("warning: line editing not enabled"). So I recommend putting these binds into `.bash_profile` instead. Even better, they can be put into `.inputrc` but they need to be suitably formatted (remove the `bind` command and the quotes). – joeytwiddle Oct 20 '21 at 09:54
  • @joeytwiddle Why do you say .inputrc is even better for these settings? – xr280xr Feb 16 '22 at 21:07
  • 1
    @xr280xr An assumption on my part that `.inputrc` is where they are "supposed" to go (and may reduce parsing by bash). But on investigation, I see that bindings put into `.inputrc` will be used not only by bash, but by all programs which use readline! – joeytwiddle Feb 17 '22 at 02:36
17

On top of

# cycle forward
Control-k: menu-complete
# cycle backward
Control-j: menu-complete-backward

you may also consider adding

# display one column with matches
set completion-display-width 1

This way you would preserve the current Tab functionality and make bash display the possibilities in one column. So instead of

file_12340983421 file_12390983421 file_12390986421 file_12391983421

you would get

file_12340983421
file_12390983421
file_12390986421
file_12391983421

P.S. You can get up to date readline library from this The GNU Readline Library website.

Johnny Baloney
  • 3,409
  • 1
  • 33
  • 37
7

Thanks to @sth I found what works best for me:

To keep normal bash tab completion, and then use ctl-f to cycle through when needed using menu-complete

put this in your .inputrc file:

"\C-f": menu-complete
pixelearth
  • 13,674
  • 10
  • 62
  • 110
1

In my experience, the solution provided in sth's answer has never completely worked for me. TL;DR: Add set -o vi to your ~/.bashrc.

When using menu-complete in conjunction with vi keybindings, I have to make sure that my ~/.bashrc has:

set -o vi

It's never been enough for my ~/.inputrc just to have:

TAB: menu-complete

set editing-mode vi
set keymap vi

My guess is that somehow set editing-mode and set keymap are clobbering the TAB: ... setting, but I haven't looked into the documentation thoroughly to figure out why this is the case.

Bruno Bronosky
  • 66,273
  • 12
  • 162
  • 149
jez
  • 1,239
  • 1
  • 7
  • 14
  • I am getting TAB command not found. I tried setting editing mode and keymap to vi but still nothing, no bash commands are found in my inputrc on macOS – Mladen Petrovic Nov 22 '16 at 10:58
  • 1
    @MladenPetrovic - the first `set...` part goes in `~/.bashrc`, the second `TAB:...` part goes in `~/.inputrc`. You'd get `TAB command not found` if you put that part in `~/.bashrc`. – Terry Brown Jul 06 '17 at 18:08
  • You probably don't need `set keymap vi` anyways : https://stackoverflow.com/questions/10002356/what-does-set-keymap-vi-do – cassepipe Sep 30 '22 at 12:46