Bash 스크립트에 자체 자동 완성 기능이 포함될 수 있나요?

Bash 스크립트에 자체 자동 완성 기능이 포함될 수 있나요?

사용할 수 있는 리소스가 많습니다(1,2,) 명령과 인수를 자동 완성하는 bash의 기능을 활용하는 방법을 설명합니다. 하지만 이러한 모든 리소스를 사용하려면 사용자에게 코드를 추가해야 합니까, ~/.bash_profile아니면 /etc/bash_completion.d/*스크립트와 사용 가능한 완성 기능을 자체 포함할 수 있는 방법이 있습니까? 조잡한 것과불완전한예:

~/bin/script-with-integrated-autocomplete.sh:

#!/usr/bin/env bash

function _completions {
  complete ...
}

if [ "$1" == "completions" ]; then
  _completions
  exit 0
fi

# (Whatever the script really does goes here.)
# ...
# ...

이 질문의 맥락에서 문제는 위의 예를 완료 ~/bin/script-with-integrated-autocomplete.sh completions하려면 이와 같은 항목을 추가해야 한다는 것입니다 .profile.

개별 bash 스크립트(파일)가 자체 완성을 선언하고 bash가 이를 인식하도록 하는 방법이 있습니까?전화할 때(추가 시스템이나 환경 설정이 없는 것이 바람직함)?

답변1

귀하의 질문에 대한 설명에서 언급했듯이 Bash는 이전 구성이나 현재 환경을 변경하지 않고는 명령줄을 완료할 수 없습니다. Bash는 파일을 보지 않으며 명시적으로 실행하거나 획득하지 않는 한 파일을 해석하려고 시도하지 않습니다.

이 주제에 대해 제가 이해한 바는 이러한 기능이 호환성 및 리소스 문제로 인해 조만간 Bash에 제공될 가능성이 낮다는 것입니다. 쉘로서 다양한 시스템에서 안정적으로 실행될 수 있어야 하고 다양한 용도로 적용할 수 있어야 합니다. 다양한 사용자 선호도를 가지며 개발자와 유지관리자는 단 한 사람입니다1 .

Bash는 자동 완성을 구현하는 도구를 제공하지만 완성 생성기는 외부 기능으로 설계된 것으로 보입니다. 실제로, 기존 도구와 약간의 작업을 통해 원하는 것을 쉽게 얻을 수 있습니다.

예제 스크립트를 보면 다음과 같습니다 foo.

#!/bin/bash

# Setting up completion for foo. Only if the script is sourced
if [ "$0" != "$BASH_SOURCE" ]; then
    _foo() {
        local cur
        COMPREPLY=()
        cur="${COMP_WORDS[COMP_CWORD]}"
        COMPREPLY=( $(compgen -W 'bar baz' -- "$cur") )
        return 0
    }
    complete -F "_foo" "foo"
    return
fi

# The body of foo -- what it does when executed
echo foo "$*"
# ...

사용배쉬 완료foo, 동적으로 로드된 사용자 완성이 저장되는 디렉토리에 심볼릭 링크를 추가하여 자체 포함 자동 완성을 활성화할 수 있습니다.

ln -s /path/to/foo ~/.local/share/bash-completion/completions/

정확한 경로는 다를 수 있습니다. bash-completion의 FAQ를 참조하여 시스템에서 해당 값을 확인하는 방법을 알아볼 수 있습니다.

bash 완료가 없으면 특정 조건을 충족하는 경우 명령(해당 파일)을 제공하는 기본 완료 기능을 정의하는 것이 한 가지 접근 방식일 수 있습니다. 여기서는 연관 배열을 화이트리스트로 사용합니다(시스템의 모든 명령을 맹목적으로 가져오는 것을 방지하기 위해). 이 코드는 .bashrc대화형 셸을 시작할 때마다 현재 환경에서 얻는 파일(또는 동등한 파일) 에 추가되어야 합니다 .

_default_completion () {
    # Do nothing when completion is invoked for an empty command
    if [ "$1" = "" ]; then
        return 1
    fi
    # Get the command path, exit with failure if it can't be found
    cmd=$(type -p "$1") || return 1
    if [ "${_compwhitelist["${cmd##*/}"]}" = y ]; then
        # Source the file corresponding to the command; on success,
        # return 124 to trigger a new autocompletion attempt
        source "$cmd" && return 124
    fi
}
complete -D -F _default_completion -o bashdefault -o default

# The list of commands with embedded completion
declare -A _compwhitelist
_compwhitelist[foo]=y

나는 당신이 구성 파일을 편집할 필요가 없는 솔루션을 요구하고 있다는 것을 알고 있지만, 어느 정도의 구성이 필요하다는 점에 유의하십시오.언제나필수의. 이 중 대부분은 배포판/패키지 관리자가 수행하지만 사용자는 이를 전혀 깨닫지 못합니다.

1참고자료 :배쉬 홈 페이지Chet Ramey의 웹사이트로 이동하여 해당 Bash에서 "A1"을 클릭하세요.자주하는 질문.

답변2

예, 그럴 수 있습니다. 당신이 해야 할 일은 환경 변수 COMP_LINE이 설정되어 있는지 확인한 다음 사용 가능한 모든 자동 완성 옵션을 간단히 에코하는 것입니다. 옵션당 한 줄씩 입력한 다음 스크립트를 종료합니다. 스크립트는 쉘 스크립트일 필요도 없습니다. Python, PHP, Golang 등 무엇이든 가능합니다.

의사코드:

if COMP_LINE {
  echo "Foo"
  echo "Bar"
  Exit 0
}

//Rest of the script here

그런 다음 쉘 자동 완성 규칙에 스크립트를 추가하기만 하면 됩니다.

완료 -C /usr/bin/the_script.sh the_script.sh

이제 "the_script.sh <tab> <tab>"을 입력하면 "foo,bar" 옵션이 표시됩니다.

답변3

쉘을 열고 입력하면 asdfasdf Tab자동으로 완료되는 것을 볼 수 있습니다 $CWD.

이를 위해 호출된 "기본 완성"을 찾아 래퍼를 만들면 한 가지 수정 사항이 모든 스크립트에 적용됩니다.

래퍼는 포함된 완성을 확인한 다음 원래 완성으로 돌아갈 수 있습니다. 모든 스크립트는 제안하는 표준을 준수해야 합니다. 나는 response COMP_LINECOMP_WORDSenv vars가 좋은 선택이 될 것이라고 생각합니다.

이미 누군가가 이 작업을 수행한 것 같습니다. 나는 내 아이디어가 획기적인 것이라고 결코 생각하지 않습니다.

관련 정보