
カンマを区切り文字として使用して、ファイル形式拡張の除外情報と埋め込み情報を含むbash関数に、コマンドライン引数として渡される2つの変数があります。
excl="el"
excl="el,htm"
incl="texi,org"
除外オプションと埋め込みオプションを使用excl
して解析したいです。incl
grep
excl="el,htm"
incl="texi,org"
grep -hir --exclude=\*.{el,htm} --include=\*.{org,texi} "$@"
excl="el"
incl="texi,org"
grep -hir --exclude=\*.el --include=\*.{org,texi} "$@"
答え1
個々の文字列を追跡するには配列を使用する必要があります。単一の文字列を使用して複数の値を保存すると、区切り文字を含むサフィックス(,v
CVSやRCSファイルのサフィックスなど)を含むコードは使用できません。
exclude=( .el .htm )
include=( .texi .org )
opts=( -h -i -r )
for ext in "${exclude[@]}"; do
opts+=( --exclude="*$ext" )
done
for ext in "${include[@]}"; do
opts+=( --include="*$ext" )
done
grep "${opts[@]}" "$@"
これにより、ファイル名のサフィックスが2つの配列exclude
に格納されますinclude
。次に、2つの配列の要素を繰り返して、という3番目の配列に適切なオプションを追加しますopts
。次に、の呼び出しで3番目の配列を使用しますgrep
。
たとえば、配列を拡張するときに使用される二重引用符は、"${opts[@]}"
個々の配列要素が二重引用符で囲まれ、シェルで分割されたりワイルドカードを使用できなくなったりします。
関数として、包含および除外されたファイル名のサフィックスのリストを2つの別々の引数として使用します。
call_grep () {
local -n include="$1"
local -n exclude="$2"
shift 2
local opts=( -h -i -r )
local ext
for ext in "${exclude[@]}"; do
opts+=( --exclude="*$ext" )
done
for ext in "${include[@]}"; do
opts+=( --include="*$ext" )
done
grep "${opts[@]}" "$@"
}
スクリプトの主な部分:
excl=( .el .htm )
incl=( .texi .org )
call_grep incl excl more arguments here
call_grep
これは、2つの配列の名前を取得する関数を設定します。最初の配列は含めるファイル名のサフィックス配列、2番目の配列は除外するサフィックス配列です。関数はこれらの配列の名前を受け取り、それを使用して2つのローカル名参照変数を設定します。grep
Pass as-は3番目のパラメータで始まります。
繰り返しますが、実際のコマンドライン解析を使用すると、次のようになりますcall_grep
。
call_grep () {
OPTIND=1
local ext opt
local opts=( -h -i -r )
while getopts 'i:e:' opt; do
case $opt in
i)
local -n include="$OPTARG"
for ext in "${include[@]}"; do
opts+=( --include="*$ext" )
done
;;
e)
local -n exclude="$OPTARG"
for ext in "${exclude[@]}"; do
opts+=( --exclude="*$ext" )
done
;;
*)
echo 'Error in option parsing' >&2
exit 1
esac
done
shift "$(( OPTIND - 1 ))"
grep "${opts[@]}" "$@"
}
これで、関数は1つと-i
1つ-e
の引数(両方ともオプション)を受け入れます。各オプションの引数は、含めるまたは除外するファイル名のサフィックスを含む配列の名前でなければなりません。
次のように使用できます。
excl=( .el .htm )
incl=( .texi .org )
call_grep -i incl -e excl -- more arguments here
--
に直接渡す必要があるパラメータと関数のパラメータを分離するには、を使用する必要がありますgrep
。
grep
シェルモードや長いオプションに言及せずに単に呼び出す方法だけが欲しい場合:
call_grep () {
OPTIND=1
while getopts 'i:e:' opt; do
case $opt in
i) opts+=( --include="*$OPTARG" ) ;;
e) opts+=( --exclude="*$OPTARG" ) ;;
*) echo 'error' >&2; exit 1
esac
done
shift "$(( OPTIND - 1 ))"
grep "${opts[@]}" "$@"
}
繰り返し使用して複数のサフィックスを含めることができ、-i suffix
同様にサフィックスを除外することもできます。例えば、
call_grep -i .texi -e .el -e .htm -i .org -- other arguments for grep here
または
call_grep -i{.texi,.org} -e{.htm,.el} -- more here for grep
答え2
フォームで拡張リストを取得するにはel,htm
:誘惑を受ける中かっこ拡張を使用するのと同様の操作を実行します。
eval 'echo grep -hir --exclude=*.{'"$excl"'} "$@"'
しかし、一般的な注意事項とは別にeval
、例えば引用符がないセミコロンはコマンドを終了して構文を混乱させます。拡張が 1 つだけ含まれている場合、または拡張がまったくない場合$excl
でも機能しません。grep
$excl
{foo}
{}
いいえ支柱の拡張として扱われます。だから中かっこ拡張を忘れよう。
実際、上記のKusalanandaの答えのように、配列にパラメータリストを作成します。条件付きで引数をスクリプトに渡す
カンマを区切り文字として保持しながらカンマで区切る簡単な方法は、配列を作成することで、オプションのリストを作成するread -a
には別の配列が必要です。
excl="el,htm"
IFS=, read -r -a exts <<< "$excl"
opts=()
for ext in "${exts[@]}"; do
opts+=(--exclude="*.$ext")
done
grep -hir "${opts[@]}" "$@"
注釈が示すように、RCSなどの拡張は、ドットで始まらない他の,v
拡張と同様に、ここで問題になります。拡張子を文字列として提供するには、代わりにコロン、セミコロン、またはスペースを区切り文字として許可し、必要に応じて区切り文字で明示的にドットを入力するようにユーザーに要求できます:
。
excl=".html:,v"
IFS=: read -r -a exts <<< "$excl"
opts=()
for ext in "${exts[@]}"; do
opts+=(--exclude="*$ext")
done
grep -hir "${opts[@]}" "$@"
もちろん、区切り文字として使用することを選択した文字は拡張の一部にすることはできませんが、セミコロンとコロンはカンマよりもまれに使用されます。