xargsにバイナリではなくエイリアスを使用させる


13

CentOS 6.5のBash 4.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=alwaysgrepコマンドに明示的に追加する必要がありました。

  • xargsな環境でのエイリアスを読んでいませんか?
  • そうでない場合、それを行う方法はありますか?

このQ&Aには必要なものがあります。
プシモン14

@psimon正しい、それは本質的に私の回避策で既にやったことをすることを言っている- xargsコマンドでエイリアスを手動で展開しなければならなかった。私が見つけようとしているのは、からエイリアスを直接呼び出すことができる方法があるかどうかxargsです。
MattDMo 14

1
export GREP_OPTIONS='-n --color=always'xargsコマンドの前に試しましたか?
doneal24 14

@ DougO'Nealありがとう、うまくいきました!それを私の.bash_profile。気軽に答えを書いてください...
MattDMo

回答:


10

エイリアスは、それが定義されているシェルの内部にあります。他のプロセスからは見えません。同じことがシェル関数にも当てはまります。xargsは別個のアプリケーションであり、シェルではないため、エイリアスまたは関数の概念はありません。

xargsにgrep直接起動する代わりにシェルを起動させることができます。ただし、シェルを呼び出すだけでは十分ではないため、そのシェルでもエイリアスを定義する必要があります。エイリアスがで定義されている場合、.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 … スペースを含むファイル名(特に)ブレークすることに注意してください。これを修正するには、ヌル区切りのレコードに変更します。

find . -name '*.py' -print0 | xargs -0 "${BASH_ALIASES[grep]}" regex_here

またはを使用して-exec

find . -name '*.py' -exec "${BASH_ALIASES[grep]}" regex_here {} +

を呼び出す代わりにfind、シェル内ですべてを実行できます。globパターン**/は、ディレクトリを再帰的に走査します。bashでは、shopt -s globstar最初にこのglobパターンを有効にするために実行する必要があります。

grep regex_here **/*.py

これにはいくつかの制限があります。

  • 多数のファイルが一致する場合(またはパスが長い場合)、コマンドラインの最大長を超えるため、コマンドが失敗する場合があります。
  • bash≤4.2では(ただし、最新バージョンでもkshやzshでも)、**/ディレクトリへのシンボリックリンクに再帰します。

別のアプローチは、MariusMatutiaeが示唆するように、プロセス置換使用することです

grep regex_here <(find . -name '*.py')

これは、**/適用できない場合に便利です。複雑なfind式の場合、またはシンボリックリンクで再帰したくない場合のbash≤4.2の場合。これは、スペースを含むファイル名で中断することに注意してください。回避策はglobbing設定IFSおよび無効にすることですが、少し複雑になり始めています:

(IFS=$'\n'; set -f; grep regex_here <(find . -name '*.py') )

エイリアスは、他のプロセスに表示されていない理由の明確な説明をありがとう
MattDMo

プロセス置換を使用することもできます。私の答えをご覧ください。
MariusMatutiae 14

11

使用する 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.

そのおかげで、私はトレーリングスペースのトリックについて知りませんでした。
MattDMo

Np。それはまたと便利ですsudo...
1.61803

2

これを別のアプローチのデモンストレーションとして受け取ってください。これは関連するSOの質問にはありません 。

xargs最初の引数がエイリアスかどうかをチェックするラッパー関数を作成できます。エイリアス関数の場合は、それに応じて展開します。

正確にそれを行うコードを次に示しますが、残念ながらZシェルが必要なので、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%alias grep = "grep -n" ´                           #一致する行番号を含める
zsh%find 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% 

1

よりシンプルでエレガントなソリューションは、プロセス置換を使用することです:

grep -E 'regex_here' <( find . -name '*.py')

パイプのように新しいシェルを作成することはありません。つまり、エイリアスが定義されている元のシェルを使用しているため、出力は希望どおりになります。

リダイレクトと括弧の間にスペースを残さないように注意してください。そうしないと、bashはエラーをスローします。私の知る限り、プロセス置換はBash、Zsh、Ksh {88,93}でサポートされていますが、pdkshではサポートされていません(まだそうではないと言われています)。


pdkshの開発は終わったと思います。Mkshは多かれ少なかれ後継プロジェクトです。「かなり難しい、判明しました(解析の概念はtg @の頭の中で行われます)」
ジル「SO-悪であるのをやめる」14

プロセス置換は複雑なために良い方法ですfindあなたはそれがスペースに破るだろうと用心する必要があるものの、コマンド、およびそれが簡単になどに固定することはできませんfind | xargsに切り替えて(することができ-print0、および-0、または使用して-exec)。該当する場合**/は、よりシンプルで堅牢です。
ジル 'SO-悪であるのをやめる' 14

0

grepは、環境変数GREP_OPTIONSから一連のデフォルトオプションを読み取ります。あなたが置く場合

 export GREP_OPTIONS='--line-number --color=always'

.bashrcで変数がサブシェルに渡され、期待する結果が得られます。


ただし、コマンドが1つだけの場合を除き、入れ--line-numberたり入れたり--color=alwaysGREP_OPTIONSないでください。多くのスクリプトが破損します。--color=autoそこにいても大丈夫です、それですべてです。この行をあなたの.bashrc意志に入れることは多くのものを壊します。
ジル「SO-悪であるのをやめる」14

@Gillesエイリアスを設定したり、rootアカウントのコマンドのデフォルトオプションを上書きしたりするのは悪いことです。ユーザーアカウントにこれらのオプションを設定しても、多くの問題が発生することはほとんどありません。問題のあるユーザースクリプトは思いつきません。
doneal24

オカレンスの存在をテストする以上の方法でgrepを使用するスクリプトは、ほとんど壊れます。たとえば、/etc/init.d/cron私のシステムから:value=`egrep "^${var}=" "$ENV_FILE" | tail -n1 | cut -d= -f2` 。またはから/usr/bin/pdfjampdftitl=`printf "%s" "$PDFinfo" | grep -e … | sed -e …` 。エイリアスはスクリプトには表示されないため、問題はありません。
ジル 'SO-悪であるのをやめる' 14

@Gilles私はこのような多くのスクリプトを知っています。私が回避できないものは、一般にルート(/etc/init.d/cronなど)によってのみ実行されます。個人的に、私は持っていないすべての私のユーザーアカウントに定義されたエイリアスをも私は、コマンドのデフォルトの動作をオーバーライドするためにrcファイルまたは環境変数を経由してオプションを設定します。利便性よりも予測可能性を好みます。
doneal24

エイリアスは、スクリプトでは認識されないため、予測可能性を壊しません。以下のGREP_OPTIONSようないくつかのオプションを除いて、設定すると予測可能性が非常に悪くなります--color=auto
ジル「SO-悪であるのをやめる」14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.