ChatGPT解决这个技术问题 Extra ChatGPT

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

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.

Put bind TAB:menu-complete in .bashrc.
and use menu-complete by default
@D.BenKnoble C-n and C-p do nothing for me...
@pixelearth it may be only in vi editing mode (set -o vi)

s
sth

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.


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.
menu-complete will auto replace you input, but will not display a candidate list. Is there a way to do both?
@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
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.
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.
j
joeytwiddle

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.


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.
I have an answer for getting the latest bash (currently 5.0.2) on macOS at stackoverflow.com/a/55011144/117471
This config needs to be in .bashrc (some other answer mentions .inputrc).
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.
@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!
J
Johnny Baloney

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.


p
pixelearth

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

B
Bruno Bronosky

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.


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
@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.