ディレクトリ内のファイルを処理するために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マニュアルの次のセクションをご覧ください。
セクション: 5.2 Bash 変数(
COMP_
プレフィックス付きの変数を探す)
Linuxドキュメントプロジェクトの高度なBashスクリプトガイドも参照してください。
Bashでプログラム的に実行されるいくつかの機能の簡単な紹介については、「The Geek Stuff」のWebサイトの次の記事を参照してください。
便利な関連StackOverflow投稿もあります。