CentOS6.5のBash4.2:
私の~/.bash_profile
には、次のようなエイリアスがたくさんあります。
alias grep='grep -n --color=always'
grep
を実行すると、色の強調表示を取得し、行番号を自動的に印刷できます。以下を実行すると、強調表示は期待どおりに機能します。
$ grep -Re 'regex_here' *.py
ただし、最近これを実行したとき:
$ find . -name '*.py' | xargs grep -E 'regex_here'
結果は強調表示されず、行番号も出力されなかったため、戻って-n --color=always
をgrep
コマンドに明示的に追加する必要がありました。
xargs
は環境内のエイリアスを読み取りませんか?エイリアスは、それが定義されているシェルの内部にあります。他のプロセスには表示されません。シェル関数についても同様です。 xargs
は独立したアプリケーションであり、シェルではないため、エイリアスや関数の概念はありません。
grep
を直接呼び出す代わりに、xargsにシェルを呼び出させることができます。ただし、シェルを呼び出すだけでは不十分であり、そのシェルでもエイリアスを定義する必要があります。エイリアスが.bashrc
で定義されている場合は、そのファイルを入手できます。ただし、これは機能しない可能性があります。.bashrc
は、非対話型シェルでは意味をなさない他のタスクを実行します。
find . -name '*.py' | xargs bash -c '. ~/.bashrc; grep -E regex_here "$@"' _
正規表現を入力するときは、ネストされた引用の複雑さに注意してください。正規表現をパラメーターとしてシェルに渡すことで、作業を簡略化できます。
find . -name '*.py' | xargs bash -c '. ~/.bashrc; grep -E "$0" "$@"' regex_here
エイリアス検索は明示的に実行できます。次に、xargs
にはgrep -n --color=always
が表示されます。
find . -name '*.py' | xargs "${BASH_ALIASES[grep]}" regex_here
Zshの場合:
find . -name '*.py' | xargs $aliases[grep] regex_here
ちなみに、find … | xargs …
はスペースを含むファイル名で壊れることに注意してください(とりわけ) 。これは、nullで区切られたレコードに変更することで修正できます。
find . -name '*.py' -print0 | xargs -0 "${BASH_ALIASES[grep]}" regex_here
または-exec
を使用して:
find . -name '*.py' -exec "${BASH_ALIASES[grep]}" regex_here {} +
find
を呼び出す代わりに、シェル内ですべてを行うことができます。グロブパターン**/
は、ディレクトリを再帰的にトラバースします。 bashでは、最初にshopt -s globstar
を実行してこのグロブパターンを有効にする必要があります。
grep regex_here **/*.py
これにはいくつかの制限があります。
**/
はディレクトリへのシンボリックリンクに再帰します。別のアプローチは、 MariusMatutiae によって提案されているように、プロセス置換を使用することです。
grep regex_here <(find . -name '*.py')
これは、**/
が適用されない場合に役立ちます。複雑なfind
式の場合、またはbash≤4.2では、シンボリックリンクで再帰しない場合に便利です。これは、スペースを含むファイル名で壊れることに注意してください。回避策は、 IFS
を設定し、globbing を無効にすることですが、少し複雑になり始めています。
(IFS=$'\n'; set -f; grep regex_here <(find . -name '*.py') )
使用する alias xargs='xargs '
alias: alias [-p] [name[=value] ... ]
(snip)
A trailing space in VALUE causes the next Word to be checked for
alias substitution when the alias is expanded.
これを、関連する SO質問 で見つけることができない別のアプローチのデモとして見てください。
xargs
のラッパー関数を記述して、最初の引数がエイリアスであるかどうかを確認し、エイリアスである場合はそれに応じて展開します。
これはまさにそれを行うコードですが、残念ながらZ Shellが必要であるため、bashと1:1で実行されません(率直に言って、私はbashを使用するのに十分に使用されていない):
xargs () {
local expandalias
if [[ $(which $1) =~ "alias" ]]; then
expandalias=$(builtin alias $1)
expandalias="${${(s.'.)expandalias}[2]}"
else
expandalias=$1
fi
command xargs ${(z)expandalias} "${(z)@[2,-1]}"
}
それが機能することの証明:
zsh% エイリアスgrep = "grep -n" ´ #一致する行番号を含める zsh% foo -name "* .p *"を検索| xargs grep-Eテスト foo/bar.p0:151:#data = test foo/bar.p1:122:#data = test#行番号が含まれています zsh% unalias grep zsh% find foo -name "* .p *" | xargs grep-Eテスト foo/bar.p0:#data = test foo/bar.p1:#data = test#行番号は含まれていません zsh%
より単純でより洗練された解決策は、 プロセス置換 を使用することです。
grep -E 'regex_here' <( find . -name '*.py')
パイプのように新しいシェルは作成されません。つまり、エイリアスが定義されている元のシェルにとどまり、出力は希望どおりになります。
リダイレクトと括弧の間にスペースを入れないように注意してください。そうしないと、bashがエラーをスローします。私の知る限り、プロセス置換はBash、Zsh、Ksh {88,93}でサポートされていますが、pdkshではサポートされていません(まだ)。
grepは、環境変数GREP_OPTIONSからデフォルトオプションのセットを読み取ります。あなたが置く場合
export GREP_OPTIONS='--line-number --color=always'
.bashrcで、変数がサブシェルに渡され、期待どおりの結果が得られます。