bash関数で "grep | grep"コマンドを文字列として実行するには?

bash関数で

bash関数で、あるgrepコマンドの結果を別のgrepコマンドにパイプするコマンドを作成しようとしています。最終的に私が実行したいコマンドは次のとおりです。

grep -I -r FooBar /code/internal/dev/ /code/public/dev/ | grep .c:\|.h:

私が作成している関数は、コマンドの最初の部分を文字列に保存してから2番目の部分を追加します。

grep_cmd="grep -I -r $pattern $@"

if (( ${#file_types[@]} > 0 )); then
    file_types="${file_types[@]}"
    file_types=.${file_types// /':\|.'}:

    grep_cmd="$grep_cmd | grep $file_types"
fi

echo "$grep_cmd"
${grep_cmd}

出力の最初の部分の後にエラーが発生します。

grep: |: No such file or directory
grep: grep: No such file or directory
grep: .c:\|.h:: No such file or directory

最後の行をからに変更すると、最初の部分の出力のみが${grep_cmd}表示され、他のエラーが発生します。"$grep_cmd"

bash: grep -I -r FooBar /code/internal/dev/ /code/public/dev/ | grep .c:\|.h:: No such file or directory

すべてこの回答、最後の行を$(grep_cmd)。別のエラーが発生します。

bash: grep_cmd: command not found

この回答お勧めしますeval $grep_cmd。これはエラーを抑制するだけでなく、出力も抑制します。

これ推奨eval ${grep_cmd}結果は同じです(エラーと出力の抑制)。私はbashでデバッグを有効にしようとしました(使用してset -x)、次のような結果が得られました。

+ eval grep -I -r FooBar /code/internal/dev/ /code/public/dev/ '|' grep '.c:\|.h:'
++ grep -I -r FooBar /code/internal/dev/ /code/public/dev/
++ grep '.c:|.h:'

パイプがエスケープされているように見えるので、シェルはコマンドを2つのコマンドとして解釈します。パイプ文字を正しくエスケープしてコマンドとして解釈するにはどうすればよいですか?

ベストアンサー1

コメントで述べたように、あなたが経験している多くの困難は、コマンドを変数に保存してから後でコマンドを実行しようとするためです。

コマンドを保存しようとする代わりに、すぐにコマンドを実行すると、はるかに良い幸運を享受できます。

たとえば、次は達成したいことをする必要があります。

if (( ${#file_types[@]} > 0 )); then
    regex="${file_types[*]}"
    regex="\.\(${regex// /\|}\):"
    grep -I -r "$pattern" "$@" | grep "$regex"
else
    grep -I -r "$pattern" "$@"
fi

おすすめ記事