When you type something, you often use bash autocompletion: you start writing a command, for example, and you type TAB
to get the rest of the word.
As you have probably noticed, when multiple choices match your command, bash displays them like this :
foobar@myserv:~$ admin- admin-addrsync admin-adduser admin-delrsync admin-deluser admin-listsvn admin-addsvn admin-chmod admin-delsvn admin-listrsync
I'm looking for a solution to display each possible solution on a new line, similar to the last column on a ls -l
. Ever better, it would be perfect if I could apply a rule like this: "if you find less than 10 suggestions, display them one by line, if more => actual display".
If you want to enable the completion for all users, you can just copy the script under /etc/bash_completion. d/ and it will automatically be loaded by Bash.
Running make install will place the scripts to $(sysconfdir)/bash_completion. d/ , thus, the user should specify --sysconfdir=/etc at configuration. If OVS is installed from packages, the scripts will automatically be placed inside /etc/bash_completion.
Bash completion is a functionality through which Bash helps users type their commands more quickly and easily. It does this by presenting possible options when users press the Tab key while typing a command.
bash
prior to version 4.2 doesn't allow any control over the output format of completions, unfortunately.
Bash 4.2+ allows switching to 1-suggestion-per-line output globally, as explained in Grisha Levit's helpful answer, which also links to a clever workaround to achieve a per-completion-function solution.
The following is a tricky workaround for a custom completion. Solving this problem generically, for all defined completions, would be much harder (if there were a way to invoke readline
functions directly, it might be easier, but I haven't found a way to do that).
To test the proof of concept below:
. file
) in your interactive shell - this will: foo
(a shell function) foo
is actually invoked, it simply prints its argument in diagnostic form.)foo [fileNamePrefix]
, then press tab: Limitations:
$PS1
, a workaround (inspired by https://stackoverflow.com/a/24006864/45375) is used, which should work in typical cases, but is not foolproof.Approach:
>/dev/tty
, and then the prompt and command line are manually "redrawn" to mimic standard completion behavior.# Define the command (function) for which to establish custom command completion. # The command simply prints out all its arguments in diagnostic form. foo() { local a i=0; for a; do echo "\$$((i+=1))=[$a]"; done; } # Define the completion function that will generate the set of completions # when <tab> is pressed. # CAVEAT: # Only works properly if <tab> is pressed at the END of the command line, # i.e., if completion is applied to the LAST argument. _complete_foo() { local currToken="${COMP_WORDS[COMP_CWORD]}" matches matchCount # Collect matches, providing the current command-line token as input. IFS=$'\n' read -d '' -ra matches <<<"$(compgen -A file "$currToken")" # Count matches. matchCount=${#matches[@]} # Output in custom format, depending on the number of matches. if (( matchCount > 1 && matchCount < 10 )); then # Output matches in CUSTOM format: # print the matches line by line, directly to the terminal. printf '\n%s' "${matches[@]}" >/dev/tty # !! We actually *must* pass out the current token as the result, # !! as it will otherwise be *removed* from the redrawn line, # !! even though $COMP_LINE *includes* that token. # !! Also, by passing out a nonempty result, we avoid the bell # !! signal that normally indicates a failed completion. # !! However, by passing out a single result, a *space* will # !! be appended to the last token - unless the compspec # !! (mapping established via `complete`) was defined with # !! `-o nospace`. COMPREPLY=( "$currToken" ) # Finally, simulate redrawing the command line. # Obtain an *expanded version* of `$PS1` using a trick # inspired by https://stackoverflow.com/a/24006864/45375. # !! This is NOT foolproof, but hopefully works in most cases. expandedPrompt=$(PS1="$PS1" debian_chroot="$debian_chroot" "$BASH" --norc -i </dev/null 2>&1 | sed -n '${s/^\(.*\)exit$/\1/p;}') printf '\n%s%s' "$expandedPrompt" "$COMP_LINE" >/dev/tty else # Just 1 match or 10 or more matches? # Perform NORMAL completion: let bash handle it by # reporting matches via array variable `$COMPREPLY`. COMPREPLY=( "${matches[@]}" ) fi } # Map the completion function (`_complete_foo`) to the command (`foo`). # `-o nospace` ensures that no space is appended after a completion, # which is needed for our workaround. complete -o nospace -F _complete_foo -- foo
bash
4.2+ (and, more generally, applications using readline
6.2+) support this with the use of the completion-display-width
variable.
The number of screen columns used to display possible matches when performing completion. The value is ignored if it is less than 0 or greater than the terminal screen width. A value of 0 will cause matches to be displayed one per line. The default value is -1.
Run the following to set the behavior for all completions1 for your current session:
bind 'set completion-display-width 0'
Or modify your ~/.inputrc
2 file to have:
set completion-display-width 0
to change the behavior for all new shells.
1 See here for a method for controlling this behavior for individual custom completion functions.
2 The search path for the readline init file is $INPUTRC
, ~/.inputrc
, /etc/inputrc
so modify the file appropriate for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With