Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm using SaltStack. I would like to auto-complete the minion name when calling salt command.

The following line has been added into ~/.bashrc:

complete -o default -o nospace -W "$(sudo ls -1 /var/cache/salt/master/minions)" salt

Then typing salt in<tab> --> salt integration-<tab>, I can see it works as expected:

$ salt integration-
integration-c   integration-u   integration-u2

To use with sudo, I have added complete -cf sudo into ~/.bashrc, but it didn't work: sudo salt in<tab returned nothing.

I also have tried to install bash_completion and added the following lines to ~/.bash_profile:

if [ -f $(brew --prefix)/etc/bash_completion ]; then
    . $(brew --prefix)/etc/bash_completion
fi

but no luck.

Did I miss something?


UPDATE Sat Jul 12 08:51:23 ICT 2014

Oh, the first thing I would like to say is sometime it works:

$ sudo salt integration-
integration-c   integration-u   integration-u2 

sometime it doesn't.

So first, let's see how much your bash_completion package does.

How can I check that? Here's my function:

# a wrapper method for the next one, when the offset is unknown
_command()
{
    local offset i

    # find actual offset, as position of the first non-option
    offset=1
    for (( i=1; i <= COMP_CWORD; i++ )); do
        if [[ "${COMP_WORDS[i]}" != -* ]]; then
            offset=$i
            break
        fi
    done
    _command_offset $offset
}

# A meta-command completion function for commands like sudo(8), which need to
# first complete on a command, then complete according to that command's own
# completion definition - currently not quite foolproof (e.g. mount and umount
# don't work properly), but still quite useful.
#
_command_offset()
{
    local cur func cline cspec noglob cmd i char_offset word_offset \
        _COMMAND_FUNC _COMMAND_FUNC_ARGS

    word_offset=$1

    # rewrite current completion context before invoking
    # actual command completion

    # find new first word position, then
    # rewrite COMP_LINE and adjust COMP_POINT
    local first_word=${COMP_WORDS[$word_offset]}
    for (( i=0; i <= ${#COMP_LINE}; i++ )); do
        if [[ "${COMP_LINE:$i:${#first_word}}" == "$first_word" ]]; then
            char_offset=$i
            break
        fi
    done
    COMP_LINE=${COMP_LINE:$char_offset}
    COMP_POINT=$(( COMP_POINT - $char_offset ))

    # shift COMP_WORDS elements and adjust COMP_CWORD
    for (( i=0; i <= COMP_CWORD - $word_offset; i++ )); do
        COMP_WORDS[i]=${COMP_WORDS[i+$word_offset]}
    done
    for (( i; i <= COMP_CWORD; i++ )); do
        unset COMP_WORDS[i];
    done
    COMP_CWORD=$(( $COMP_CWORD - $word_offset ))

    COMPREPLY=()
    _get_comp_words_by_ref cur

    if [[ $COMP_CWORD -eq 0 ]]; then
        _compopt_o_filenames
        COMPREPLY=( $( compgen -c -- "$cur" ) )
    else
        cmd=${COMP_WORDS[0]}
        if complete -p ${cmd##*/} &>/dev/null; then
            cspec=$( complete -p ${cmd##*/} )
            if [ "${cspec#* -F }" != "$cspec" ]; then
                # complete -F <function>

                # get function name
                func=${cspec#*-F }
                func=${func%% *}

                if [[ ${#COMP_WORDS[@]} -ge 2 ]]; then
                    $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" "${COMP_WORDS[${#COMP_WORDS[@]}-2]}"
                else
                    $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}"
                fi

                # remove any \: generated by a command that doesn't
                # default to filenames or dirnames (e.g. sudo chown)
                # FIXME: I'm pretty sure this does not work!
                if [ "${cspec#*-o }" != "$cspec" ]; then
                    cspec=${cspec#*-o }
                    cspec=${cspec%% *}
                    if [[ "$cspec" != @(dir|file)names ]]; then
                        COMPREPLY=("${COMPREPLY[@]//\\\\:/:}")
                    else
                        _compopt_o_filenames
                    fi
                fi
            elif [ -n "$cspec" ]; then
                cspec=${cspec#complete};
                cspec=${cspec%%${cmd##*/}};
                COMPREPLY=( $( eval compgen "$cspec" -- "$cur" ) );
            fi
        elif [ ${#COMPREPLY[@]} -eq 0 ]; then
            _filedir
        fi
    fi
}

if you type sudo mkdir <tab><tab>, does it show a list of directories?

Yes:

$ sudo mkdir 
.FontForge/        .djangopypi2/      .ievms/            .ssh/              .wireshark-etc/
share|improve this question
1  
Chaining together command completions usually involves completion functions that invoke a function defined in the completion package called _command_offset. So first, let's see how much your bash_completion package does. If you remove the complete -cf sudo line from .bashrc, then logout and login again, and just use the support built in to bash_completion, do you see any special handling at all for sudo, e.g., if you type sudo mkdir <tab><tab>, does it show a list of directories? –  Mark Plotnick Jul 11 at 14:38
    
@MarkPlotnick: if you type sudo mkdir <tab><tab>, does it show a list of directories? --> Yes, see my update in the original question. –  quanta Jul 12 at 4:49
    
If completion chaining is sometimes working and sometimes not, the first thing I'd check is the completion definition for sudo when completions are not working. Do this by typing complete|grep sudo. Bash on OSX reads its init files in nonintuitive ways (see apple.stackexchange.com/a/13019), so my hunch is that sometimes not all your completion definitions are being read in or they are being superseded by unwanted definitions. –  Mark Plotnick Jul 14 at 21:29

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.