Is it possible to make bash auto-completion look like in Cisco IOS shell?
I mean to add short descriptions for each completion, like this:
telnet 10.10.10. (TAB Pressed)
10.10.10.10 - routerA
10.10.10.11 - routerB
where 10.10.10.10 and 10.10.10.11 are possible completions and routerA & routerB just descriptions (not to be executed).
I know that bash can complete commands with "complete -W", but is it able to print descriptions for them?
Bash completion is a bash function that allows you to auto complete commands or arguments by typing partially commands or arguments, then pressing the [Tab] key. This will help you when writing the bash command in terminal.
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.
When at the MS-DOS, Windows command line or a Linux or Unix shell, typing in long file names or directories can become a burden. Use the Tab to autocomplete the names of directories and files while in the command line.
If you want completion within your program, you normally have to find matches starting with a particular string. This might be done by populating all possible values in a std::map, then using lower_bound and/or upper_bound to find the currently matching completions.
I have a solution to this that does not require pressing TAB more than twice or echoing any extra information. The key is to check whether there is only one completion, then strip that completion down to the valid portion, usually by removing the largest matching suffix after your "comment" delimiter. To accomplish the OP's example:
_telnet() {
COMPREPLY=()
local cur
cur=$(_get_cword)
local completions="10.10.10.10 - routerA
10.10.10.11 - routerB
10.20.1.3 - routerC"
local OLDIFS="$IFS"
local IFS=$'\n'
COMPREPLY=( $( compgen -W "$completions" -- "$cur" ) )
IFS="$OLDIFS"
if [[ ${#COMPREPLY[*]} -eq 1 ]]; then #Only one completion
COMPREPLY=( ${COMPREPLY[0]%% - *} ) #Remove ' - ' and everything after
fi
return 0
}
complete -F _telnet -A hostnames telnet
This gives the exact output you're looking for, and when there is only one possible completion, the comment is stripped from it before completing.
I'd use conversion based on whether the number of candidates become one (as shown by @bonsaiviking) for simple cases and the following if I needed more flexibility in what I want to show the user.
__foo () {
local WORDS
WORDS=("1|10.10.10.10|routerA" "2|10.10.10.11|routerB")
local FOR_DISPLAY=1
if [ "${__FOO_PREV_LINE:-}" != "$COMP_LINE" ] ||
[ "${__FOO_PREV_POINT:-}" != "$COMP_POINT" ]; then
__FOO_PREV_LINE=$COMP_LINE
__FOO_PREV_POINT=$COMP_POINT
FOR_DISPLAY=
fi
local IFS=$'\n'
COMPREPLY=($(
for WORD in "${WORDS[@]}"; do
IFS=\| read -ra SP <<<"$WORD"
if [ "${SP[1]:0:${#2}}" == "$2" ]; then
if [ -n "$FOR_DISPLAY" ]; then
printf "%-*s\n" "$COLUMNS" "${SP[0]}: ${SP[1]} - ${SP[2]}"
else
echo "${SP[1]}"
fi
fi
done
))
}
complete -F __foo x
Note: You could probably use COMP_TYPE
to set FOR_DISPLAY
in Bash 4.x but I needed to support Bash 3.x as well.
This behaves as follows:
$ x 1
Tab
$ x 10.10.10.1
TabTab
1: 10.10.10.10 - routerA
2: 10.10.10.11 - routerB
$ x 10.10.10.1
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