Bash 매개변수 자동 완성

Bash 매개변수 자동 완성

디렉토리의 파일을 처리하기 위해 bash를 작성 중입니다. 작업할 몇 가지 기본(상당히 긴) 경로가 있습니다. 옵션과 매개변수를 통해 하위 경로를 지정하고 자동 완성이 가능하도록 만들고 싶습니다. 내 말은 이것이다:

#!/bin/bash

dir=~/path/to/base/dir

while getopts ":d:" opt; do
    case $opt in
      d)
         dir=$dir/$OPTARG
         ;;
      #invalid input handling
    esac
done

하지만 이 구현에서는 매개변수가 자동 완성되지 않으며 하위 디렉터리의 모든 이름을 직접 입력해야 합니다( Tab작동하지 않음).

Bash에서 이것을 달성하는 방법이 있습니까?

답변1

예, 명령줄 옵션 플래그로 지정된 사용자 정의 기본 디렉터리에서 경로 완성을 수행할 수 있습니다. 이를 달성하는 방법에 대한 간단한 예는 다음과 같습니다. 먼저 데모를 좀 더 흥미롭게 만들기 위해 예제 스크립트를 약간 수정하겠습니다(즉, 출력 생성).

#!/bin/bash

# echo_path.sh
#
#    Echoes a path.
#

# Parse command-line options
while getopts ":d:" opt; do

    # Use '-d' to specify relative path
    case "${opt}" in
    d)
        directory="${OPTARG}"
        ;;
    esac
done

# Print the full path
echo "$(readlink -f ${directory})"

이는 기본적으로 예제 스크립트와 동일하지만 제공된 인수를 인쇄합니다.

다음으로 Bash 프로그래밍을 통해 시스템 호출을 완료하는 함수를 작성해야 합니다. 다음은 이러한 함수를 정의하는 스크립트입니다.

# echo_path_completion.bash

# Programmatic path completion for user specified file paths.

# Define a base directory for relative paths.
export BASE_DIRECTORY=/tmp/basedir

# Define the completion function
function _echo_path_completion() {

    # Define local variables to store adjacent pairs of arguments
    local prev_arg;
    local curr_arg;

    # If there are at least two arguments then we have a candidate
    # for path-completion, i.e. we need the option flag '-d' and
    # the path string that follows it.
    if [[ ${#COMP_WORDS[@]} -ge 2 ]]; then

        # Get the current and previous arguments from the command-line
        prev_arg="${COMP_WORDS[COMP_CWORD-1]}";
        curr_arg="${COMP_WORDS[COMP_CWORD]}";

        # We only want to do our custom path-completion if the previous
        # argument is the '-d' option flag
        if [[ "${prev_arg}" = "-d" ]]; then

            # We only want to do our custom path-completion if a base
            # directory is defined and the argument is a relative path
            if [[ -n "${BASE_DIRECTORY}" && ${curr_arg} != /* ]]; then

                # Generate the list of path-completions starting from BASE_DIRECTORY
                COMPREPLY=( $(compgen -d -o default -- "${BASE_DIRECTORY}/${curr_arg}") );

                # Don't append a space after the command-completion
                # This is so we can continue to apply completion to subdirectories
                compopt -o nospace;

                # Return immediately
                return 0;
            fi
        fi
    fi

    # If no '-d' flag is given or no base directory is defined then apply default command-completion
    COMPREPLY=( $(compgen -o default -- "${curr_arg}") );
    return 0;
}

# Activate the completion function
complete -F _echo_path_completion echo_path

이제 완성 스크립트를 가져오겠습니다.

source echo_path_completion.bash

스크립트를 실행 가능하게 만들고 경로의 어딘가로 이동해 보겠습니다.

chmod +x echo_path.bash
mv -i echo_path.bash /usr/local/bin

마지막으로 파일 확장자 없이 스크립트에 대한 별칭을 추가해 보겠습니다.

alias echo_path=echo_path.bash

echo -d이제 탭 버튼을 입력하고 클릭하면 BASE_DIRECTORY로 시작하는 파일 경로 완성이 표시됩니다. 이를 테스트하려면 다음을 시도해 보세요.

mkdir -p ${BASE_DIRECTORY}
mkdir -p "${BASE_DIRECTORY}/file"{1..5}

Tab을 클릭하면 다음 완성 목록이 표시됩니다.

user@host:~$ echo_path -d
user@host:~$ echo_path -d /tmp/basedir/file
/tmp/basedir/file1  /tmp/basedir/file2  /tmp/basedir/file3  /tmp/basedir/file4  /tmp/basedir/file5

첫 번째 탭 이후에는 문자열이 절대 경로로 변환됩니다. 원하는 경우 이를 변경할 수 있지만 아마도 이것이 더 나은 동작이라고 생각합니다.

자세한 내용을 확인할 수 있는 몇 가지 참고 자료는 다음과 같습니다.

공식적인 참고 자료는 Bash 매뉴얼의 다음 섹션을 확인하세요.

Linux 문서 프로젝트의 고급 Bash 스크립팅 가이드도 참조하세요.

Bash에서 프로그래밍 방식으로 수행되는 일부 기능에 대한 간략한 소개는 "The Geek Stuff" 웹사이트의 다음 기사를 참조하세요.

유용한 관련 StackOverflow 게시물도 있습니다.

관련 정보