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」のWebサイトの次の記事を参照してください。

便利な関連StackOverflow投稿もあります。

関連情報