sudo를 사용할 때 bash가 내 명령을 자동 완성하지 않습니까?

sudo를 사용할 때 bash가 내 명령을 자동 완성하지 않습니까?

솔트스택을 사용하고 있습니다. salt명령을 호출할 때 미니언 이름을 자동 완성 하고 싶습니다 .

다음 줄이 에 추가되었습니다 ~/.bashrc.

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

그런 다음 → 를 입력하면 예상대로 작동하는 것을 볼 수 있습니다.salt inTabsalt integration-Tab

$ 소금 통합- TabTab
통합-c 통합-u 통합-u2

에 사용하기 위해 을 추가 sudo했지만 작동하지 않습니다.complete -cf sudo~/.bashrc

    스도 소금Tab

아무것도 반환되지 않습니다.

bash_completion또한 다음 줄을 설치하고 추가해 보았습니다 ~/.bash_profile.

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

하지만 행운은 없습니다.

내가 놓친 게 무엇입니까?


고쳐 쓰다

아, 제가 가장 먼저 말씀드리고 싶은 것은 가끔은 효과가 있다는 것입니다.

$ sudo 솔트 통합 TabTab
-integrate-c 통합-u 통합-u2

때로는 그렇지 않습니다.

먼저 bash_completion 패키지의 기능이 얼마나 되는지 살펴보겠습니다.

어떻게 확인하나요? 이것은 내 기능입니다.

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

을 입력하면 sudo mkdirTabTab디렉토리 목록이 표시됩니까?

예:

$ sudo mkdir TabTab
.FontForge/ .djangopypi2/ .ievms/ .ssh/ .wireshark-etc/

답변1

set -o가능한 모드가 활성화되어 있는지 확인하십시오 posix. 그렇다면 비활성화하십시오.set +o posix

"posix" 모드에서는 어떤 이유로 "vi 모드"에서 bash의 탭 완성이 비활성화됩니다. 왜 이런 동작이 발생했는지, 왜 vi 모드에만 해당되는지에 대한 설명이 없었기 때문에 굳이 설명하지 않았습니다.

추신: 이 답변은 특정 설정에 대한 것이 아니라 검색 엔진을 통해 우연히 질문을 발견한 사람을 위한 것입니다.

고쳐 쓰다:
쳇 레이미설명하다:

POSIX 모드에서는 탭 매핑을 통해 vi 편집 모드를 수행하면 안 됩니다. 이는 POSIX.2가 vi 편집 모드의 동작을 완전히 지정하고 표준에서는 탭이 기본적으로 자체 삽입에 매핑되도록 요구하기 때문입니다.

답변2

빠른 답변:

  • 설치하다bash-completion
  • 원천bash_completionBash시작에
  • Bash시작 시 구성 요소 추가
  • sudo다음으로 compspec을 재정의 하지 마십시오 .complete -cf sudo

MacOSX를 사용하고 계신 것 같아요 brew.

노력하다:

brew update
brew install bash-completion
brew info bash-completion
# bash-completion: stable 1.3
. $(brew --prefix)/etc/bash_completion
complete -p sudo

다음과 같은 내용이 표시됩니다.

complete -F _root_command sudo

시험:

function _comp_foo() { COMPREPLY=($(compgen -W 'a b c' -- "$2")); }
complete -F _comp_foo foo

foo SpaceTabTab
당신이 봐야 할 유형a b c

sudo foo SpaceTabTab
당신이 봐야 할 유형a b c

complete -fc sudo그런 다음 초기화 파일 ~/.bash_profile( ~/.bashrc등) 에서 제거합니다
. 초기화 파일에 다음 줄을 추가합니다.

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

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

터미널을 다시 엽니다.
유형 complete -p sudo.
당신은 그것을 확인해야합니다 complete -F _root_command sudo.

유형 complete -p salt.
다음과 같은 내용이 표시됩니다.

complete -o default -o nospace -W 'a
b
c' salt

bash-completion2.* 참고:
다음을 설치할 수 있습니다 bash-completion2.https://github.com/Homebrew/homebrew/issues/19258
하지만:

  • 2.*그리고Bash 4.*
  • 2.*-Dcompspecs 지연 로딩 옵션을 사용하십시오 . 따라서 complete -p sudo출력은 complete: sudo: no completion specification입력할 때까지 입니다.sudoSpaceTab

답변3

sudo요청을 사용하지 않는 한 로그인 쉘이 제공되지 않습니다 -i. 따라서 이것이 없으면 시스템 완성을 로드해야 한다는 것을 알게 될 것입니다:

. /etc/bash_completion

run 을 사용하면 사용자에게 작성된 모든 내용을 읽을 수 없게 됩니다 -i. 완성을 나머지 부분과 분리할 수 있다면 및 를 사용하여 가져오면 작동할 것입니다.$HOME~root~/.bashrc~/.bashrc.

관련 정보