How can I make bash tab completion behave like vim tab completion and cycle through matching matches?

BashShellVim

Bash Problem Overview


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 a horrible bore 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.

Bash Solutions


Solution 1 - Bash

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.

Solution 2 - Bash

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'

# 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 is another nice pair of bindings:

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

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.

Solution 3 - Bash

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.

Solution 4 - Bash

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

Solution 5 - Bash

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpixelearthView Question on Stackoverflow
Solution 1 - BashsthView Answer on Stackoverflow
Solution 2 - BashjoeytwiddleView Answer on Stackoverflow
Solution 3 - BashJohnny BaloneyView Answer on Stackoverflow
Solution 4 - BashpixelearthView Answer on Stackoverflow
Solution 5 - BashjezView Answer on Stackoverflow