How to customize Bash command completion?












22















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 locTABlocalc. And my brother, who prompted me to ask this, wants it with mplayer).










share|improve this question


















  • 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











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





    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
















22















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 locTABlocalc. And my brother, who prompted me to ask this, wants it with mplayer).










share|improve this question


















  • 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











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





    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














22












22








22


8






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 locTABlocalc. And my brother, who prompted me to ask this, wants it with mplayer).










share|improve this question














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 locTABlocalc. And my brother, who prompted me to ask this, wants it with mplayer).







bash autocomplete






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Aug 5 '14 at 12:29









derobertderobert

72.6k8153210




72.6k8153210








  • 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











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





    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














  • 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











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





    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








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










4 Answers
4






active

oldest

votes


















9





+200









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






share|improve this answer

































    1














    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.






    share|improve this answer































      0














      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






      share|improve this answer





















      • 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



















      -3














      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.






      share|improve this answer



















      • 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













      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
      });


      }
      });














      draft saved

      draft discarded


















      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









      9





      +200









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






      share|improve this answer






























        9





        +200









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






        share|improve this answer




























          9





          +200







          9





          +200



          9




          +200





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






          share|improve this answer















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







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 8 at 17:18

























          answered Jul 23 '15 at 16:36









          mr.spuraticmr.spuratic

          6,8411028




          6,8411028

























              1














              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.






              share|improve this answer




























                1














                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.






                share|improve this answer


























                  1












                  1








                  1







                  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.






                  share|improve this answer













                  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.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Aug 8 '14 at 10:41









                  m13rm13r

                  8291814




                  8291814























                      0














                      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






                      share|improve this answer





















                      • 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
















                      0














                      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






                      share|improve this answer





















                      • 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














                      0












                      0








                      0







                      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






                      share|improve this answer















                      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







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      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














                      • 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











                      -3














                      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.






                      share|improve this answer



















                      • 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


















                      -3














                      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.






                      share|improve this answer



















                      • 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
















                      -3












                      -3








                      -3







                      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.






                      share|improve this answer













                      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.







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










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
















                      • 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










                      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




















                      draft saved

                      draft discarded




















































                      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.




                      draft saved


                      draft discarded














                      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





















































                      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







                      Popular posts from this blog

                      How to make a Squid Proxy server?

                      Is this a new Fibonacci Identity?

                      19世紀