How to customize Bash command completion?
In bash, it's easy enough to set up customized completion of command arguments using the complete
built-in. For example, if, for a hypothetical command with a synopsis of foo --a | --b | --c
, you could do complete -W '--a --b --c' foo
You can also customize the completion you get when you press Tab at an empty prompt using complete -E
, e.g., complete -E -W 'foo bar'
. Then pressing tab at the empty prompt would suggest only foo
and bar
.
How do I customize command completion at a non-empty prompt? E.g., if I'm sitting at:
anthony@Zia:~$ f
how do customize completion so pressing tab would always complete to foo
?
(The actual case I'd like is loc
TAB → localc
. And my brother, who prompted me to ask this, wants it with mplayer).
bash autocomplete
|
show 1 more comment
In bash, it's easy enough to set up customized completion of command arguments using the complete
built-in. For example, if, for a hypothetical command with a synopsis of foo --a | --b | --c
, you could do complete -W '--a --b --c' foo
You can also customize the completion you get when you press Tab at an empty prompt using complete -E
, e.g., complete -E -W 'foo bar'
. Then pressing tab at the empty prompt would suggest only foo
and bar
.
How do I customize command completion at a non-empty prompt? E.g., if I'm sitting at:
anthony@Zia:~$ f
how do customize completion so pressing tab would always complete to foo
?
(The actual case I'd like is loc
TAB → localc
. And my brother, who prompted me to ask this, wants it with mplayer).
bash autocomplete
2
Have you considered simply aliasingloc
tolocalc
? I suggest alternatives because after quite some time digging and searching I have not found a way to customize bash completion this way. It may not be possible.
– jw013
Aug 5 '14 at 20:47
@jw013 Yeah, I looked for a while and couldn't find anything either. I'm half expecting someone to suggest switching to zsh, too. At least if zsh does it, I can rest comfortably knowing the next version of bash will as well. 😀
– derobert
Aug 5 '14 at 20:51
you have to press TAB twice and it will complete commands.
– Floyd
Oct 10 '14 at 15:30
Won't that break all the other completions though? I mean, even if it is possible, you would no longer be able to getlocate
,locale
,lockfile
or any of the other expansions ofloc
. Perhaps a better approach would be to map a different key to that specific completion.
– terdon♦
Oct 28 '14 at 18:00
1
can you give an example of such context (that would lead to the desired effect to beloc<TAB>->localc
)?
– damienfrancois
Nov 4 '14 at 14:29
|
show 1 more comment
In bash, it's easy enough to set up customized completion of command arguments using the complete
built-in. For example, if, for a hypothetical command with a synopsis of foo --a | --b | --c
, you could do complete -W '--a --b --c' foo
You can also customize the completion you get when you press Tab at an empty prompt using complete -E
, e.g., complete -E -W 'foo bar'
. Then pressing tab at the empty prompt would suggest only foo
and bar
.
How do I customize command completion at a non-empty prompt? E.g., if I'm sitting at:
anthony@Zia:~$ f
how do customize completion so pressing tab would always complete to foo
?
(The actual case I'd like is loc
TAB → localc
. And my brother, who prompted me to ask this, wants it with mplayer).
bash autocomplete
In bash, it's easy enough to set up customized completion of command arguments using the complete
built-in. For example, if, for a hypothetical command with a synopsis of foo --a | --b | --c
, you could do complete -W '--a --b --c' foo
You can also customize the completion you get when you press Tab at an empty prompt using complete -E
, e.g., complete -E -W 'foo bar'
. Then pressing tab at the empty prompt would suggest only foo
and bar
.
How do I customize command completion at a non-empty prompt? E.g., if I'm sitting at:
anthony@Zia:~$ f
how do customize completion so pressing tab would always complete to foo
?
(The actual case I'd like is loc
TAB → localc
. And my brother, who prompted me to ask this, wants it with mplayer).
bash autocomplete
bash autocomplete
asked Aug 5 '14 at 12:29
derobertderobert
72.6k8153210
72.6k8153210
2
Have you considered simply aliasingloc
tolocalc
? I suggest alternatives because after quite some time digging and searching I have not found a way to customize bash completion this way. It may not be possible.
– jw013
Aug 5 '14 at 20:47
@jw013 Yeah, I looked for a while and couldn't find anything either. I'm half expecting someone to suggest switching to zsh, too. At least if zsh does it, I can rest comfortably knowing the next version of bash will as well. 😀
– derobert
Aug 5 '14 at 20:51
you have to press TAB twice and it will complete commands.
– Floyd
Oct 10 '14 at 15:30
Won't that break all the other completions though? I mean, even if it is possible, you would no longer be able to getlocate
,locale
,lockfile
or any of the other expansions ofloc
. Perhaps a better approach would be to map a different key to that specific completion.
– terdon♦
Oct 28 '14 at 18:00
1
can you give an example of such context (that would lead to the desired effect to beloc<TAB>->localc
)?
– damienfrancois
Nov 4 '14 at 14:29
|
show 1 more comment
2
Have you considered simply aliasingloc
tolocalc
? I suggest alternatives because after quite some time digging and searching I have not found a way to customize bash completion this way. It may not be possible.
– jw013
Aug 5 '14 at 20:47
@jw013 Yeah, I looked for a while and couldn't find anything either. I'm half expecting someone to suggest switching to zsh, too. At least if zsh does it, I can rest comfortably knowing the next version of bash will as well. 😀
– derobert
Aug 5 '14 at 20:51
you have to press TAB twice and it will complete commands.
– Floyd
Oct 10 '14 at 15:30
Won't that break all the other completions though? I mean, even if it is possible, you would no longer be able to getlocate
,locale
,lockfile
or any of the other expansions ofloc
. Perhaps a better approach would be to map a different key to that specific completion.
– terdon♦
Oct 28 '14 at 18:00
1
can you give an example of such context (that would lead to the desired effect to beloc<TAB>->localc
)?
– damienfrancois
Nov 4 '14 at 14:29
2
2
Have you considered simply aliasing
loc
to localc
? I suggest alternatives because after quite some time digging and searching I have not found a way to customize bash completion this way. It may not be possible.– jw013
Aug 5 '14 at 20:47
Have you considered simply aliasing
loc
to localc
? I suggest alternatives because after quite some time digging and searching I have not found a way to customize bash completion this way. It may not be possible.– jw013
Aug 5 '14 at 20:47
@jw013 Yeah, I looked for a while and couldn't find anything either. I'm half expecting someone to suggest switching to zsh, too. At least if zsh does it, I can rest comfortably knowing the next version of bash will as well. 😀
– derobert
Aug 5 '14 at 20:51
@jw013 Yeah, I looked for a while and couldn't find anything either. I'm half expecting someone to suggest switching to zsh, too. At least if zsh does it, I can rest comfortably knowing the next version of bash will as well. 😀
– derobert
Aug 5 '14 at 20:51
you have to press TAB twice and it will complete commands.
– Floyd
Oct 10 '14 at 15:30
you have to press TAB twice and it will complete commands.
– Floyd
Oct 10 '14 at 15:30
Won't that break all the other completions though? I mean, even if it is possible, you would no longer be able to get
locate
, locale
, lockfile
or any of the other expansions of loc
. Perhaps a better approach would be to map a different key to that specific completion.– terdon♦
Oct 28 '14 at 18:00
Won't that break all the other completions though? I mean, even if it is possible, you would no longer be able to get
locate
, locale
, lockfile
or any of the other expansions of loc
. Perhaps a better approach would be to map a different key to that specific completion.– terdon♦
Oct 28 '14 at 18:00
1
1
can you give an example of such context (that would lead to the desired effect to be
loc<TAB>->localc
)?– damienfrancois
Nov 4 '14 at 14:29
can you give an example of such context (that would lead to the desired effect to be
loc<TAB>->localc
)?– damienfrancois
Nov 4 '14 at 14:29
|
show 1 more comment
4 Answers
4
active
oldest
votes
Completion of the command (along with other things) is handled via bash readline completion. This operates at a slightly lower level than the usual "programmable completion" (which is invoked only when the command is identified, and the two special cases you identified above).
Update: the new release of bash-5.0 (Jan 2019) adds complete -I
for exactly this problem.
The relevant readline commands are:
complete (TAB)
Attempt to perform completion on the text before point. Bash
attempts completion treating the text as a variable (if the text
begins with $), username (if the text begins with ~), hostname
(if the text begins with @), or command (including aliases and
functions) in turn. If none of these produces a match, filename
completion is attempted.
complete-command (M-!)
Attempt completion on the text before point, treating it as a
command name. Command completion attempts to match the text
against aliases, reserved words, shell functions, shell
builtins, and finally executable filenames, in that order.
In a similar way to the more common complete -F
, some of this can be handed over to a function by using bind -x
.
function _complete0 () {
local -a _cmds
local -A _seen
local _path=$PATH _ii _xx _cc _cmd _short
local _aa=( ${READLINE_LINE} )
if [[ -f ~/.complete.d/"${_aa[0]}" && -x ~/.complete.d/"${_aa[0]}" ]]; then
## user-provided hook
_cmds=( $( ~/.complete.d/"${_aa[0]}" ) )
elif [[ -x ~/.complete.d/DEFAULT ]]; then
_cmds=( $( ~/.complete.d/DEFAULT ) )
else
## compgen -c for default "command" complete
_cmds=( $(PATH=$_path compgen -o bashdefault -o default -c ${_aa[0]}) )
fi
## remove duplicates, cache shortest name
_short="${_cmds[0]}"
_cc=${#_cmds[*]} # NB removing indexes inside loop
for (( _ii=0 ; _ii<$_cc ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmd]}" ]] && unset _cmds[$_ii]
_seen[$_cmd]+=1
(( ${#_short} > ${#_cmd} )) && _short="$_cmd"
done
_cmds=( "${_cmds[@]}" ) ## recompute contiguous index
## find common prefix
declare -a _prefix=()
for (( _xx=0; _xx<${#_short}; _xx++ )); do
_prev=${_cmds[0]}
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ "${_cmd:$_xx:1}" != "${_prev:$_xx:1}" ]] && break
_prev=$_cmd
done
[[ $_ii -eq ${#_cmds[*]} ]] && _prefix[$_xx]="${_cmd:$_xx:1}"
done
printf -v _short "%s" "${_prefix[@]}" # flatten
## emulate completion list of matches
if [[ ${#_cmds[*]} -gt 1 ]]; then
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmds]}" ]] && printf "%-12s " "$_cmd"
done | sort | fmt -w $((COLUMNS-8)) | column -tx
# fill in shortest match (prefix)
printf -v READLINE_LINE "%s" "$_short"
READLINE_POINT=${#READLINE_LINE}
fi
## exactly one match
if [[ ${#_cmds[*]} -eq 1 ]]; then
_aa[0]="${_cmds[0]}"
printf -v READLINE_LINE "%s " "${_aa[@]}"
READLINE_POINT=${#READLINE_LINE}
else
: # nop
fi
}
bind -x '"C-i":_complete0'
This enables your own per-command or prefix string hooks in ~/.complete.d/
. E.g. if you create an executable ~/.complete.d/loc
with:
#!/bin/bash
echo localc
This will do (roughly) what you expect.
The function above goes to some lengths to emulate the normal bash command completion behaviour, though it is imperfect (particularly the dubious sort | fmt | column
carry-on to display a list of matches).
However, a non-trivial issue with this it can only use a function to replace the binding to the main complete
function (invoked with TAB by default).
This approach would work well with a different key-binding used for just custom command completion, but it simply does not implement the full completion logic after that (e.g. later words in the command line). Doing so would require parsing the command line, dealing with cursor position, and other tricky things that probably should not be considered in a shell script...
add a comment |
I don't know if I unterstood your need for this...
This would imply that your bash only knows one command beginning with f
.
A basic idea of completion is: if it's ambiguous, print the possiblities.
So you could set your PATH
to a directory only containing this one command and disable all bash builtins to get this work.
Anyhow, I can give you also a kind of workaround:
alias _='true &&'
complete -W foo _
So if you type _ <Tab>
it will complete to _ foo
which executes foo
.
But nethertheless the alias f='foo'
would be much easier.
add a comment |
Simple answer for you would be to
$ cd into /etc/bash_completion.d
$ ls
just the basic outputs
autoconf gpg2 ntpdate shadow
automake gzip open-iscsi smartctl
bash-builtins iconv openssl sqlite3
bind-utils iftop perl ssh
brctl ifupdown pkg-config strace
bzip2 info pm-utils subscription-manager
chkconfig ipmitool postfix tar
configure iproute2 procps tcpdump
coreutils iptables python util-linux
cpio lsof quota-tools wireless-tools
crontab lvm redefine_filedir xmllint
cryptsetup lzma rfkill xmlwf
dd make rpm xz
dhclient man rsync yum.bash
e2fsprogs mdadm scl.bash yum-utils.bash
findutils module-init-tools service
getent net-tools sh
just add your desired program to auto complete to bash completion
2
Those files have shell script in them, some fairly complex if I remember correctly. Also, they only complete arguments once you've already typed the command... They don't complete the command.
– derobert
Sep 25 '14 at 3:41
I understand what you mean. When you can take a look at this doc: debian-administration.org/article/316/…
– unixmiah
Sep 25 '14 at 3:53
add a comment |
Run the below command to find where mplayer binary is installed:
which mplayer
OR use the path to the mplayer binary if you aleady know it, in the below command:
ln -s /path/to/mplayer /bin/mplayer
Ideally anything you type is searched in all directories specified in the $PATH
variable.
2
Hi, Mathew, welcome to Unix & Linux. I think the OP's question is a little more complicated than the answer you're suggesting. I presumemplayer
is already in their$PATH
and they want something likemp<tab>
to producemplayer
, instead of all the binaries that begin withmp
(e.g.,mpage
mpcd
mpartition
mplayer
etc.)
– drs
Oct 15 '14 at 14:48
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f148497%2fhow-to-customize-bash-command-completion%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
Completion of the command (along with other things) is handled via bash readline completion. This operates at a slightly lower level than the usual "programmable completion" (which is invoked only when the command is identified, and the two special cases you identified above).
Update: the new release of bash-5.0 (Jan 2019) adds complete -I
for exactly this problem.
The relevant readline commands are:
complete (TAB)
Attempt to perform completion on the text before point. Bash
attempts completion treating the text as a variable (if the text
begins with $), username (if the text begins with ~), hostname
(if the text begins with @), or command (including aliases and
functions) in turn. If none of these produces a match, filename
completion is attempted.
complete-command (M-!)
Attempt completion on the text before point, treating it as a
command name. Command completion attempts to match the text
against aliases, reserved words, shell functions, shell
builtins, and finally executable filenames, in that order.
In a similar way to the more common complete -F
, some of this can be handed over to a function by using bind -x
.
function _complete0 () {
local -a _cmds
local -A _seen
local _path=$PATH _ii _xx _cc _cmd _short
local _aa=( ${READLINE_LINE} )
if [[ -f ~/.complete.d/"${_aa[0]}" && -x ~/.complete.d/"${_aa[0]}" ]]; then
## user-provided hook
_cmds=( $( ~/.complete.d/"${_aa[0]}" ) )
elif [[ -x ~/.complete.d/DEFAULT ]]; then
_cmds=( $( ~/.complete.d/DEFAULT ) )
else
## compgen -c for default "command" complete
_cmds=( $(PATH=$_path compgen -o bashdefault -o default -c ${_aa[0]}) )
fi
## remove duplicates, cache shortest name
_short="${_cmds[0]}"
_cc=${#_cmds[*]} # NB removing indexes inside loop
for (( _ii=0 ; _ii<$_cc ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmd]}" ]] && unset _cmds[$_ii]
_seen[$_cmd]+=1
(( ${#_short} > ${#_cmd} )) && _short="$_cmd"
done
_cmds=( "${_cmds[@]}" ) ## recompute contiguous index
## find common prefix
declare -a _prefix=()
for (( _xx=0; _xx<${#_short}; _xx++ )); do
_prev=${_cmds[0]}
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ "${_cmd:$_xx:1}" != "${_prev:$_xx:1}" ]] && break
_prev=$_cmd
done
[[ $_ii -eq ${#_cmds[*]} ]] && _prefix[$_xx]="${_cmd:$_xx:1}"
done
printf -v _short "%s" "${_prefix[@]}" # flatten
## emulate completion list of matches
if [[ ${#_cmds[*]} -gt 1 ]]; then
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmds]}" ]] && printf "%-12s " "$_cmd"
done | sort | fmt -w $((COLUMNS-8)) | column -tx
# fill in shortest match (prefix)
printf -v READLINE_LINE "%s" "$_short"
READLINE_POINT=${#READLINE_LINE}
fi
## exactly one match
if [[ ${#_cmds[*]} -eq 1 ]]; then
_aa[0]="${_cmds[0]}"
printf -v READLINE_LINE "%s " "${_aa[@]}"
READLINE_POINT=${#READLINE_LINE}
else
: # nop
fi
}
bind -x '"C-i":_complete0'
This enables your own per-command or prefix string hooks in ~/.complete.d/
. E.g. if you create an executable ~/.complete.d/loc
with:
#!/bin/bash
echo localc
This will do (roughly) what you expect.
The function above goes to some lengths to emulate the normal bash command completion behaviour, though it is imperfect (particularly the dubious sort | fmt | column
carry-on to display a list of matches).
However, a non-trivial issue with this it can only use a function to replace the binding to the main complete
function (invoked with TAB by default).
This approach would work well with a different key-binding used for just custom command completion, but it simply does not implement the full completion logic after that (e.g. later words in the command line). Doing so would require parsing the command line, dealing with cursor position, and other tricky things that probably should not be considered in a shell script...
add a comment |
Completion of the command (along with other things) is handled via bash readline completion. This operates at a slightly lower level than the usual "programmable completion" (which is invoked only when the command is identified, and the two special cases you identified above).
Update: the new release of bash-5.0 (Jan 2019) adds complete -I
for exactly this problem.
The relevant readline commands are:
complete (TAB)
Attempt to perform completion on the text before point. Bash
attempts completion treating the text as a variable (if the text
begins with $), username (if the text begins with ~), hostname
(if the text begins with @), or command (including aliases and
functions) in turn. If none of these produces a match, filename
completion is attempted.
complete-command (M-!)
Attempt completion on the text before point, treating it as a
command name. Command completion attempts to match the text
against aliases, reserved words, shell functions, shell
builtins, and finally executable filenames, in that order.
In a similar way to the more common complete -F
, some of this can be handed over to a function by using bind -x
.
function _complete0 () {
local -a _cmds
local -A _seen
local _path=$PATH _ii _xx _cc _cmd _short
local _aa=( ${READLINE_LINE} )
if [[ -f ~/.complete.d/"${_aa[0]}" && -x ~/.complete.d/"${_aa[0]}" ]]; then
## user-provided hook
_cmds=( $( ~/.complete.d/"${_aa[0]}" ) )
elif [[ -x ~/.complete.d/DEFAULT ]]; then
_cmds=( $( ~/.complete.d/DEFAULT ) )
else
## compgen -c for default "command" complete
_cmds=( $(PATH=$_path compgen -o bashdefault -o default -c ${_aa[0]}) )
fi
## remove duplicates, cache shortest name
_short="${_cmds[0]}"
_cc=${#_cmds[*]} # NB removing indexes inside loop
for (( _ii=0 ; _ii<$_cc ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmd]}" ]] && unset _cmds[$_ii]
_seen[$_cmd]+=1
(( ${#_short} > ${#_cmd} )) && _short="$_cmd"
done
_cmds=( "${_cmds[@]}" ) ## recompute contiguous index
## find common prefix
declare -a _prefix=()
for (( _xx=0; _xx<${#_short}; _xx++ )); do
_prev=${_cmds[0]}
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ "${_cmd:$_xx:1}" != "${_prev:$_xx:1}" ]] && break
_prev=$_cmd
done
[[ $_ii -eq ${#_cmds[*]} ]] && _prefix[$_xx]="${_cmd:$_xx:1}"
done
printf -v _short "%s" "${_prefix[@]}" # flatten
## emulate completion list of matches
if [[ ${#_cmds[*]} -gt 1 ]]; then
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmds]}" ]] && printf "%-12s " "$_cmd"
done | sort | fmt -w $((COLUMNS-8)) | column -tx
# fill in shortest match (prefix)
printf -v READLINE_LINE "%s" "$_short"
READLINE_POINT=${#READLINE_LINE}
fi
## exactly one match
if [[ ${#_cmds[*]} -eq 1 ]]; then
_aa[0]="${_cmds[0]}"
printf -v READLINE_LINE "%s " "${_aa[@]}"
READLINE_POINT=${#READLINE_LINE}
else
: # nop
fi
}
bind -x '"C-i":_complete0'
This enables your own per-command or prefix string hooks in ~/.complete.d/
. E.g. if you create an executable ~/.complete.d/loc
with:
#!/bin/bash
echo localc
This will do (roughly) what you expect.
The function above goes to some lengths to emulate the normal bash command completion behaviour, though it is imperfect (particularly the dubious sort | fmt | column
carry-on to display a list of matches).
However, a non-trivial issue with this it can only use a function to replace the binding to the main complete
function (invoked with TAB by default).
This approach would work well with a different key-binding used for just custom command completion, but it simply does not implement the full completion logic after that (e.g. later words in the command line). Doing so would require parsing the command line, dealing with cursor position, and other tricky things that probably should not be considered in a shell script...
add a comment |
Completion of the command (along with other things) is handled via bash readline completion. This operates at a slightly lower level than the usual "programmable completion" (which is invoked only when the command is identified, and the two special cases you identified above).
Update: the new release of bash-5.0 (Jan 2019) adds complete -I
for exactly this problem.
The relevant readline commands are:
complete (TAB)
Attempt to perform completion on the text before point. Bash
attempts completion treating the text as a variable (if the text
begins with $), username (if the text begins with ~), hostname
(if the text begins with @), or command (including aliases and
functions) in turn. If none of these produces a match, filename
completion is attempted.
complete-command (M-!)
Attempt completion on the text before point, treating it as a
command name. Command completion attempts to match the text
against aliases, reserved words, shell functions, shell
builtins, and finally executable filenames, in that order.
In a similar way to the more common complete -F
, some of this can be handed over to a function by using bind -x
.
function _complete0 () {
local -a _cmds
local -A _seen
local _path=$PATH _ii _xx _cc _cmd _short
local _aa=( ${READLINE_LINE} )
if [[ -f ~/.complete.d/"${_aa[0]}" && -x ~/.complete.d/"${_aa[0]}" ]]; then
## user-provided hook
_cmds=( $( ~/.complete.d/"${_aa[0]}" ) )
elif [[ -x ~/.complete.d/DEFAULT ]]; then
_cmds=( $( ~/.complete.d/DEFAULT ) )
else
## compgen -c for default "command" complete
_cmds=( $(PATH=$_path compgen -o bashdefault -o default -c ${_aa[0]}) )
fi
## remove duplicates, cache shortest name
_short="${_cmds[0]}"
_cc=${#_cmds[*]} # NB removing indexes inside loop
for (( _ii=0 ; _ii<$_cc ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmd]}" ]] && unset _cmds[$_ii]
_seen[$_cmd]+=1
(( ${#_short} > ${#_cmd} )) && _short="$_cmd"
done
_cmds=( "${_cmds[@]}" ) ## recompute contiguous index
## find common prefix
declare -a _prefix=()
for (( _xx=0; _xx<${#_short}; _xx++ )); do
_prev=${_cmds[0]}
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ "${_cmd:$_xx:1}" != "${_prev:$_xx:1}" ]] && break
_prev=$_cmd
done
[[ $_ii -eq ${#_cmds[*]} ]] && _prefix[$_xx]="${_cmd:$_xx:1}"
done
printf -v _short "%s" "${_prefix[@]}" # flatten
## emulate completion list of matches
if [[ ${#_cmds[*]} -gt 1 ]]; then
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmds]}" ]] && printf "%-12s " "$_cmd"
done | sort | fmt -w $((COLUMNS-8)) | column -tx
# fill in shortest match (prefix)
printf -v READLINE_LINE "%s" "$_short"
READLINE_POINT=${#READLINE_LINE}
fi
## exactly one match
if [[ ${#_cmds[*]} -eq 1 ]]; then
_aa[0]="${_cmds[0]}"
printf -v READLINE_LINE "%s " "${_aa[@]}"
READLINE_POINT=${#READLINE_LINE}
else
: # nop
fi
}
bind -x '"C-i":_complete0'
This enables your own per-command or prefix string hooks in ~/.complete.d/
. E.g. if you create an executable ~/.complete.d/loc
with:
#!/bin/bash
echo localc
This will do (roughly) what you expect.
The function above goes to some lengths to emulate the normal bash command completion behaviour, though it is imperfect (particularly the dubious sort | fmt | column
carry-on to display a list of matches).
However, a non-trivial issue with this it can only use a function to replace the binding to the main complete
function (invoked with TAB by default).
This approach would work well with a different key-binding used for just custom command completion, but it simply does not implement the full completion logic after that (e.g. later words in the command line). Doing so would require parsing the command line, dealing with cursor position, and other tricky things that probably should not be considered in a shell script...
Completion of the command (along with other things) is handled via bash readline completion. This operates at a slightly lower level than the usual "programmable completion" (which is invoked only when the command is identified, and the two special cases you identified above).
Update: the new release of bash-5.0 (Jan 2019) adds complete -I
for exactly this problem.
The relevant readline commands are:
complete (TAB)
Attempt to perform completion on the text before point. Bash
attempts completion treating the text as a variable (if the text
begins with $), username (if the text begins with ~), hostname
(if the text begins with @), or command (including aliases and
functions) in turn. If none of these produces a match, filename
completion is attempted.
complete-command (M-!)
Attempt completion on the text before point, treating it as a
command name. Command completion attempts to match the text
against aliases, reserved words, shell functions, shell
builtins, and finally executable filenames, in that order.
In a similar way to the more common complete -F
, some of this can be handed over to a function by using bind -x
.
function _complete0 () {
local -a _cmds
local -A _seen
local _path=$PATH _ii _xx _cc _cmd _short
local _aa=( ${READLINE_LINE} )
if [[ -f ~/.complete.d/"${_aa[0]}" && -x ~/.complete.d/"${_aa[0]}" ]]; then
## user-provided hook
_cmds=( $( ~/.complete.d/"${_aa[0]}" ) )
elif [[ -x ~/.complete.d/DEFAULT ]]; then
_cmds=( $( ~/.complete.d/DEFAULT ) )
else
## compgen -c for default "command" complete
_cmds=( $(PATH=$_path compgen -o bashdefault -o default -c ${_aa[0]}) )
fi
## remove duplicates, cache shortest name
_short="${_cmds[0]}"
_cc=${#_cmds[*]} # NB removing indexes inside loop
for (( _ii=0 ; _ii<$_cc ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmd]}" ]] && unset _cmds[$_ii]
_seen[$_cmd]+=1
(( ${#_short} > ${#_cmd} )) && _short="$_cmd"
done
_cmds=( "${_cmds[@]}" ) ## recompute contiguous index
## find common prefix
declare -a _prefix=()
for (( _xx=0; _xx<${#_short}; _xx++ )); do
_prev=${_cmds[0]}
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ "${_cmd:$_xx:1}" != "${_prev:$_xx:1}" ]] && break
_prev=$_cmd
done
[[ $_ii -eq ${#_cmds[*]} ]] && _prefix[$_xx]="${_cmd:$_xx:1}"
done
printf -v _short "%s" "${_prefix[@]}" # flatten
## emulate completion list of matches
if [[ ${#_cmds[*]} -gt 1 ]]; then
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmds]}" ]] && printf "%-12s " "$_cmd"
done | sort | fmt -w $((COLUMNS-8)) | column -tx
# fill in shortest match (prefix)
printf -v READLINE_LINE "%s" "$_short"
READLINE_POINT=${#READLINE_LINE}
fi
## exactly one match
if [[ ${#_cmds[*]} -eq 1 ]]; then
_aa[0]="${_cmds[0]}"
printf -v READLINE_LINE "%s " "${_aa[@]}"
READLINE_POINT=${#READLINE_LINE}
else
: # nop
fi
}
bind -x '"C-i":_complete0'
This enables your own per-command or prefix string hooks in ~/.complete.d/
. E.g. if you create an executable ~/.complete.d/loc
with:
#!/bin/bash
echo localc
This will do (roughly) what you expect.
The function above goes to some lengths to emulate the normal bash command completion behaviour, though it is imperfect (particularly the dubious sort | fmt | column
carry-on to display a list of matches).
However, a non-trivial issue with this it can only use a function to replace the binding to the main complete
function (invoked with TAB by default).
This approach would work well with a different key-binding used for just custom command completion, but it simply does not implement the full completion logic after that (e.g. later words in the command line). Doing so would require parsing the command line, dealing with cursor position, and other tricky things that probably should not be considered in a shell script...
edited Jan 8 at 17:18
answered Jul 23 '15 at 16:36
mr.spuraticmr.spuratic
6,8411028
6,8411028
add a comment |
add a comment |
I don't know if I unterstood your need for this...
This would imply that your bash only knows one command beginning with f
.
A basic idea of completion is: if it's ambiguous, print the possiblities.
So you could set your PATH
to a directory only containing this one command and disable all bash builtins to get this work.
Anyhow, I can give you also a kind of workaround:
alias _='true &&'
complete -W foo _
So if you type _ <Tab>
it will complete to _ foo
which executes foo
.
But nethertheless the alias f='foo'
would be much easier.
add a comment |
I don't know if I unterstood your need for this...
This would imply that your bash only knows one command beginning with f
.
A basic idea of completion is: if it's ambiguous, print the possiblities.
So you could set your PATH
to a directory only containing this one command and disable all bash builtins to get this work.
Anyhow, I can give you also a kind of workaround:
alias _='true &&'
complete -W foo _
So if you type _ <Tab>
it will complete to _ foo
which executes foo
.
But nethertheless the alias f='foo'
would be much easier.
add a comment |
I don't know if I unterstood your need for this...
This would imply that your bash only knows one command beginning with f
.
A basic idea of completion is: if it's ambiguous, print the possiblities.
So you could set your PATH
to a directory only containing this one command and disable all bash builtins to get this work.
Anyhow, I can give you also a kind of workaround:
alias _='true &&'
complete -W foo _
So if you type _ <Tab>
it will complete to _ foo
which executes foo
.
But nethertheless the alias f='foo'
would be much easier.
I don't know if I unterstood your need for this...
This would imply that your bash only knows one command beginning with f
.
A basic idea of completion is: if it's ambiguous, print the possiblities.
So you could set your PATH
to a directory only containing this one command and disable all bash builtins to get this work.
Anyhow, I can give you also a kind of workaround:
alias _='true &&'
complete -W foo _
So if you type _ <Tab>
it will complete to _ foo
which executes foo
.
But nethertheless the alias f='foo'
would be much easier.
answered Aug 8 '14 at 10:41
m13rm13r
8291814
8291814
add a comment |
add a comment |
Simple answer for you would be to
$ cd into /etc/bash_completion.d
$ ls
just the basic outputs
autoconf gpg2 ntpdate shadow
automake gzip open-iscsi smartctl
bash-builtins iconv openssl sqlite3
bind-utils iftop perl ssh
brctl ifupdown pkg-config strace
bzip2 info pm-utils subscription-manager
chkconfig ipmitool postfix tar
configure iproute2 procps tcpdump
coreutils iptables python util-linux
cpio lsof quota-tools wireless-tools
crontab lvm redefine_filedir xmllint
cryptsetup lzma rfkill xmlwf
dd make rpm xz
dhclient man rsync yum.bash
e2fsprogs mdadm scl.bash yum-utils.bash
findutils module-init-tools service
getent net-tools sh
just add your desired program to auto complete to bash completion
2
Those files have shell script in them, some fairly complex if I remember correctly. Also, they only complete arguments once you've already typed the command... They don't complete the command.
– derobert
Sep 25 '14 at 3:41
I understand what you mean. When you can take a look at this doc: debian-administration.org/article/316/…
– unixmiah
Sep 25 '14 at 3:53
add a comment |
Simple answer for you would be to
$ cd into /etc/bash_completion.d
$ ls
just the basic outputs
autoconf gpg2 ntpdate shadow
automake gzip open-iscsi smartctl
bash-builtins iconv openssl sqlite3
bind-utils iftop perl ssh
brctl ifupdown pkg-config strace
bzip2 info pm-utils subscription-manager
chkconfig ipmitool postfix tar
configure iproute2 procps tcpdump
coreutils iptables python util-linux
cpio lsof quota-tools wireless-tools
crontab lvm redefine_filedir xmllint
cryptsetup lzma rfkill xmlwf
dd make rpm xz
dhclient man rsync yum.bash
e2fsprogs mdadm scl.bash yum-utils.bash
findutils module-init-tools service
getent net-tools sh
just add your desired program to auto complete to bash completion
2
Those files have shell script in them, some fairly complex if I remember correctly. Also, they only complete arguments once you've already typed the command... They don't complete the command.
– derobert
Sep 25 '14 at 3:41
I understand what you mean. When you can take a look at this doc: debian-administration.org/article/316/…
– unixmiah
Sep 25 '14 at 3:53
add a comment |
Simple answer for you would be to
$ cd into /etc/bash_completion.d
$ ls
just the basic outputs
autoconf gpg2 ntpdate shadow
automake gzip open-iscsi smartctl
bash-builtins iconv openssl sqlite3
bind-utils iftop perl ssh
brctl ifupdown pkg-config strace
bzip2 info pm-utils subscription-manager
chkconfig ipmitool postfix tar
configure iproute2 procps tcpdump
coreutils iptables python util-linux
cpio lsof quota-tools wireless-tools
crontab lvm redefine_filedir xmllint
cryptsetup lzma rfkill xmlwf
dd make rpm xz
dhclient man rsync yum.bash
e2fsprogs mdadm scl.bash yum-utils.bash
findutils module-init-tools service
getent net-tools sh
just add your desired program to auto complete to bash completion
Simple answer for you would be to
$ cd into /etc/bash_completion.d
$ ls
just the basic outputs
autoconf gpg2 ntpdate shadow
automake gzip open-iscsi smartctl
bash-builtins iconv openssl sqlite3
bind-utils iftop perl ssh
brctl ifupdown pkg-config strace
bzip2 info pm-utils subscription-manager
chkconfig ipmitool postfix tar
configure iproute2 procps tcpdump
coreutils iptables python util-linux
cpio lsof quota-tools wireless-tools
crontab lvm redefine_filedir xmllint
cryptsetup lzma rfkill xmlwf
dd make rpm xz
dhclient man rsync yum.bash
e2fsprogs mdadm scl.bash yum-utils.bash
findutils module-init-tools service
getent net-tools sh
just add your desired program to auto complete to bash completion
edited Mar 29 '15 at 20:12
Anthon
60.4k17102165
60.4k17102165
answered Sep 25 '14 at 3:33
unixmiahunixmiah
326110
326110
2
Those files have shell script in them, some fairly complex if I remember correctly. Also, they only complete arguments once you've already typed the command... They don't complete the command.
– derobert
Sep 25 '14 at 3:41
I understand what you mean. When you can take a look at this doc: debian-administration.org/article/316/…
– unixmiah
Sep 25 '14 at 3:53
add a comment |
2
Those files have shell script in them, some fairly complex if I remember correctly. Also, they only complete arguments once you've already typed the command... They don't complete the command.
– derobert
Sep 25 '14 at 3:41
I understand what you mean. When you can take a look at this doc: debian-administration.org/article/316/…
– unixmiah
Sep 25 '14 at 3:53
2
2
Those files have shell script in them, some fairly complex if I remember correctly. Also, they only complete arguments once you've already typed the command... They don't complete the command.
– derobert
Sep 25 '14 at 3:41
Those files have shell script in them, some fairly complex if I remember correctly. Also, they only complete arguments once you've already typed the command... They don't complete the command.
– derobert
Sep 25 '14 at 3:41
I understand what you mean. When you can take a look at this doc: debian-administration.org/article/316/…
– unixmiah
Sep 25 '14 at 3:53
I understand what you mean. When you can take a look at this doc: debian-administration.org/article/316/…
– unixmiah
Sep 25 '14 at 3:53
add a comment |
Run the below command to find where mplayer binary is installed:
which mplayer
OR use the path to the mplayer binary if you aleady know it, in the below command:
ln -s /path/to/mplayer /bin/mplayer
Ideally anything you type is searched in all directories specified in the $PATH
variable.
2
Hi, Mathew, welcome to Unix & Linux. I think the OP's question is a little more complicated than the answer you're suggesting. I presumemplayer
is already in their$PATH
and they want something likemp<tab>
to producemplayer
, instead of all the binaries that begin withmp
(e.g.,mpage
mpcd
mpartition
mplayer
etc.)
– drs
Oct 15 '14 at 14:48
add a comment |
Run the below command to find where mplayer binary is installed:
which mplayer
OR use the path to the mplayer binary if you aleady know it, in the below command:
ln -s /path/to/mplayer /bin/mplayer
Ideally anything you type is searched in all directories specified in the $PATH
variable.
2
Hi, Mathew, welcome to Unix & Linux. I think the OP's question is a little more complicated than the answer you're suggesting. I presumemplayer
is already in their$PATH
and they want something likemp<tab>
to producemplayer
, instead of all the binaries that begin withmp
(e.g.,mpage
mpcd
mpartition
mplayer
etc.)
– drs
Oct 15 '14 at 14:48
add a comment |
Run the below command to find where mplayer binary is installed:
which mplayer
OR use the path to the mplayer binary if you aleady know it, in the below command:
ln -s /path/to/mplayer /bin/mplayer
Ideally anything you type is searched in all directories specified in the $PATH
variable.
Run the below command to find where mplayer binary is installed:
which mplayer
OR use the path to the mplayer binary if you aleady know it, in the below command:
ln -s /path/to/mplayer /bin/mplayer
Ideally anything you type is searched in all directories specified in the $PATH
variable.
answered Oct 15 '14 at 14:21
Mathew ParetMathew Paret
3319
3319
2
Hi, Mathew, welcome to Unix & Linux. I think the OP's question is a little more complicated than the answer you're suggesting. I presumemplayer
is already in their$PATH
and they want something likemp<tab>
to producemplayer
, instead of all the binaries that begin withmp
(e.g.,mpage
mpcd
mpartition
mplayer
etc.)
– drs
Oct 15 '14 at 14:48
add a comment |
2
Hi, Mathew, welcome to Unix & Linux. I think the OP's question is a little more complicated than the answer you're suggesting. I presumemplayer
is already in their$PATH
and they want something likemp<tab>
to producemplayer
, instead of all the binaries that begin withmp
(e.g.,mpage
mpcd
mpartition
mplayer
etc.)
– drs
Oct 15 '14 at 14:48
2
2
Hi, Mathew, welcome to Unix & Linux. I think the OP's question is a little more complicated than the answer you're suggesting. I presume
mplayer
is already in their $PATH
and they want something like mp<tab>
to produce mplayer
, instead of all the binaries that begin with mp
(e.g., mpage
mpcd
mpartition
mplayer
etc.)– drs
Oct 15 '14 at 14:48
Hi, Mathew, welcome to Unix & Linux. I think the OP's question is a little more complicated than the answer you're suggesting. I presume
mplayer
is already in their $PATH
and they want something like mp<tab>
to produce mplayer
, instead of all the binaries that begin with mp
(e.g., mpage
mpcd
mpartition
mplayer
etc.)– drs
Oct 15 '14 at 14:48
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f148497%2fhow-to-customize-bash-command-completion%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Have you considered simply aliasing
loc
tolocalc
? I suggest alternatives because after quite some time digging and searching I have not found a way to customize bash completion this way. It may not be possible.– jw013
Aug 5 '14 at 20:47
@jw013 Yeah, I looked for a while and couldn't find anything either. I'm half expecting someone to suggest switching to zsh, too. At least if zsh does it, I can rest comfortably knowing the next version of bash will as well. 😀
– derobert
Aug 5 '14 at 20:51
you have to press TAB twice and it will complete commands.
– Floyd
Oct 10 '14 at 15:30
Won't that break all the other completions though? I mean, even if it is possible, you would no longer be able to get
locate
,locale
,lockfile
or any of the other expansions ofloc
. Perhaps a better approach would be to map a different key to that specific completion.– terdon♦
Oct 28 '14 at 18:00
1
can you give an example of such context (that would lead to the desired effect to be
loc<TAB>->localc
)?– damienfrancois
Nov 4 '14 at 14:29