2

I have a bash autocompletion function _customcomplete that I want to apply on a script called run.sh. If I call complete -F _customcomplete ./run.sh, then the autocompletion script works fine as long as I am in the same directory and call it with ./run.sh. However, if I go one level up and call it with ./scripts/run.sh, the autocompletion script does not work. More importantly, if I am in a different directory with another script called run.sh, the autocompletion script works on that one when it shouldn't.

In short, is it possible to tie a bash autocompletion function to a specific executable, rather than an invocation string?

Here is a full simplified example:

In completion.sh is a very simple completion script that always returns three options: one two three:

_customcomplete() {
  local word="${COMP_WORDS[COMP_CWORD]}"
  COMPREPLY=( $(compgen -W "one two three" -- "$word") )
}

I can source it with source completion.sh and can verify that it sourced with type _customcomplete:

_customcomplete is a function
_customcomplete() {
  local word="${COMP_WORDS[COMP_CWORD]}"
  COMPREPLY=( $(compgen -W "one two three" -- "$word") )
}

In a directory, I have two folders scripts and other, both of which contain a script called run.sh. Each just echos the command line arguments along with a unique message to differentiate the two.

Let us now try to register the completion function to the run.sh in scripts by cd'ing into the scripts directory and running complete -F _customcomplete ./run.sh. Now I can call ./run.sh and use tab completion to see the possibilities of one two three. However, if I try and call it from a directory above as ./scripts/run.sh, I get the default filesystem tab completion suggestions. Additionally, if I cd into other, the custom tab completion works on that script as well.

Changing the complete command to link to any sort of global path only allows the custom tab completion when using that exact same global path as the invocation string. What I want to happen is to be able to call the script by any relative path and have the custom tab completion work as expected.

2
  • 1
    Just updated my post with a full example – nardavin Aug 21 '19 at 3:38
  • Had the same problem. Eventually changed the name of my command, because name clashes hit you sooner or later. – xenoid Aug 21 '19 at 8:12
1

It seems you want to create a completion for particular instance of a command, regardless of how it is called (via absolute or relative path), but not others which may share the same name, but be located elsewhere. For instance, you might want completion for a script located at ~/bin/example.sh, but not /usr/bin/example.sh.

Based on the Bash Reference Manual: 8.6 Programmable Completion, bash complete does not have the functionality you desire built in. However, within your _customcomplete function, you can find the location of the script being called, using readlink, then customize COMPREPLY accordingly:

_customcomplete() {
    local CMD_NAME=`readlink -f "$1"`
    local word="${COMP_WORDS[COMP_CWORD]}"

    if [[ $CMD_NAME == '/home/user/bin/example.sh' ]] ; then
        COMPREPLY=( $(compgen -W "one two three" -- "$word") )
    fi
} &&

complete -F _customcomplete example.sh
5
  • I don't believe this example works if I call it from a directory besides ~/bin. Is there anything I would be able to do to get it to work when calling it from any valid path? Say, ~/bin/example.sh from anywhere or bin/example.sh from the home directory? – nardavin Aug 21 '19 at 6:57
  • 1
    readlink should resolve ~/bin/example.sh to /home/user/bin/example.sh. – xiota Aug 21 '19 at 7:01
  • Ah it actually does work after testing it. readlink wasn't what I was concerned with, but rather the complete command linking just to example.sh. I was trying to link it to ./example.sh earlier, which only worked when I invoked it from the same directory, as that was the only place that I could call it by ./example.sh. Is there any documentation on why example.sh works from any directory (for example, does it match to the suffix of the invocation string)? Anyway, thanks for the help! Problem solved. – nardavin Aug 21 '19 at 7:11
  • 8.6 Programmable Completion has an description of what's matched in what order. It looks for complete paths first, then matches by name, ignoring the path. Pretty much what you've already observed. – xiota Aug 21 '19 at 7:16
  • 1
    Edited to try to make clearer that readlink is the key. – xiota Aug 21 '19 at 7:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.