パイプを含める方法| 私のLinuxのfind -execコマンドで?


220

これは機能していません。これはfindで実行できますか?または、xargsが必要ですか?

find -name 'file_*' -follow -type f -exec zcat {} \| agrep -dEOE 'grep' \;

回答:


145

パイプ記号を複数のプロセスを実行し、あるプロセスの出力を別のプロセスの入力にパイプする命令として解釈する作業は、シェル(/ bin / shまたは同等のもの)の責任です。

あなたの例では、トップレベルのシェルを使用して次のようにパイプを実行することを選択できます:

find -name 'file_*' -follow -type f -exec zcat {} \; | agrep -dEOE 'grep'

効率の面では、この結果、findの1回の呼び出し、zcatの多数の呼び出し、およびagrepの1回の呼び出しにコストがかかります。

これにより、zcatの多数の呼び出しによって生成されたすべての出力を処理する単一のagrepプロセスのみが生成されます。

何らかの理由でagrepを複数回呼び出したい場合は、次のようにします。

find . -name 'file_*' -follow -type f \
    -printf "zcat %p | agrep -dEOE 'grep'\n" | sh

これは、パイプを使用して実行するコマンドのリストを作成し、それらを新しいシェルに送信して実際に実行します。(最後の "| sh"を省略すると、このようなコマンドラインのドライランをデバッグまたは実行するのに便利です。)

効率の面では、この結果、findの1回の呼び出し、shの1回の呼び出し、zcatの多数の呼び出し、およびagrepの多数の呼び出しにコストがかかります。

コマンド呼び出しの数に関して最も効率的な解決策は、Paul Tomblinからの提案です。

find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

... findの1回の呼び出し、xargsの1回の呼び出し、zcatの数回の呼​​び出し、およびagrepの1回の呼び出しにかかるコスト。


1
xargsのもう1つの利点は、-Pスイッチ(-P 0)を使用することにより、最新のマルチコアCPUでさらに高速化できることです。
flolo 2008年

はい、-Pスイッチは確かに一般的に実行を高速化する良い方法です。残念ながら、並列zcatプロセスの出力がインターリーブされたagrepにパイプされるリスクがあり、結果に影響を与えます。この効果は、次のコマンドを使用して確認できます:echo -e "1 \ n2" | xargs -P 0 -n 1 yes | uniq
ロルフW.ラスムッセン

@アダム、あなたが提案した変更を行いました。
Paul Tomblin、

splendid xjobsコマンドをインストールできる(元はSolarisから)
sehe

4
より簡単でより一般的な答えは、stackoverflow.com / a / 21825690/42973にあります-exec sh -c "… | … " \;
Eric O Lebigot 2015

278

解決策は簡単です:sh経由で実行

... -exec sh -c "zcat {} | agrep -dEOE 'grep' " \;

17
OPが達成しようとしていたことは上記の提案で満たすことができますが、これは実際に尋ねられた質問に答えるものです。このようにする理由はあります。execは、特にテストと組み合わせると、findによって返されたファイルを操作するよりもはるかに強力です。たとえば、geda-gaf / -type d -exec bash -c 'DIR = {};を見つけます。[[$(find $ DIR -maxdepth 1 | xargs grep -i spice | wc -l)-ge 5]] && echo $ DIR '\; スパイスという単語を含むディレクトリ内のすべてのファイルのうち、合計5行を超える検索パス内のすべてのディレクトリを返します
swarfrat

3
ベストアンサー。(他の回答が示唆するように)出力全体を把握することは、各ファイルをgrepすることと同じではありません。ヒント:shの代わりに、他の任意のシェルを使用できます(私はbashでそれを試しましたが、問題なく実行されています)。
pagliuca

1
-cオプションを見落とさないようにしてください。そうしないと、不可解なNo such file or directoryエラーメッセージが表示されます。
2013

ここでは、execされたシェル内のパイプでfindを使用する優れたpsの置き換えを示します。/ usr / bin / find / proc -mindepth 1 -maxdepth 1 -type d -regex '。* / [0-9] +'- print -exec bash -c "cat {} / cmdline | tr '\\ 0' ''; echo" \;
パリティ3 2014

1
正規表現を使用 してファイルを検索し、sedでファイル名を変更する例find -type f -name '*.mdds' -exec sh -c "echo {} | sed -e 's/_[0-9]\+//g' | xargs mv {}" \;
Rostfrei

16
find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

効率上の理由から-printとxargsを避けたい。多分それが本当に私の問題です:findは-execを介してパイプコマンドを処理できません
someguy

これは、名前にスペースが含まれているファイルでは機能しません。修正するには、-printを-print0に置き換え、xargsに-0オプションを追加します
Adam Rosenfield

2
@someguy-なに?効率上の理由からxargsを避けますか?zcatの1つのインスタンスを呼び出し、それに複数のファイルのリストを渡すと、見つかったファイルごとに新しいインスタンスを実行するよりもはるかに効率的です。
ペンドリーシェルム2008年

@Adam-提案された変更を行いました。検索を行っているときの99%は、ソースコードディレクトリにあり、そこにファイルがないため、print0を使用しません。一方、私のドキュメントディレクトリでは、print0を覚えています。
ポールトンブリン

10

検索whileして、ファイルに対して複数のアクションを実行できるループにパイプすることもできfindます。だからここにjarjarファイルの大きなディストリビューションを持つフォルダ内の特定のJavaクラスファイルのアーカイブを探すためのものがあります

find /usr/lib/eclipse/plugins -type f -name \*.jar | while read jar; do echo $jar; jar tf $jar | fgrep IObservableList ; done

重要な点は、whileループにはセミコロンで区切られた渡されたファイル名を参照する複数のコマンドが含まれており、これらのコマンドにはパイプを含めることができるということです。したがって、その例では、一致するファイルの名前をエコーし​​てから、特定のクラス名のアーカイブフィルタリングの内容を一覧表示します。出力は次のようになります。

/usr/lib/eclipse/plugins/org.eclipse.core.contenttype.source_3.4.1.R35x_v20090826-0451.jar /usr/lib/eclipse/plugins/org.eclipse.core.databinding.observable_1.2.0.M20090902-0800 .jar org / eclipse / core / databinding / observable / list / IObservableList .class /usr/lib/eclipse/plugins/org.eclipse.search.source_3.5.1.r351_v20090708-0800.jar / usr / lib / eclipse / plugins / org.eclipse.jdt.apt.core.source_3.3.202.R35x_v20091130-2300.jar /usr/lib/eclipse/plugins/org.eclipse.cvs.source_1.0.400.v201002111343.jar / usr / lib / eclipse / plugins / org.eclipse.help.appserver_3.1.400.v20090429_1800.jar

私のbashシェル(xubuntu10.04 / xfce)ではfgrep、一致した文字列が強調表示されるため、一致したクラス名が実際に太字になります。これにより、jar検索された何百ものファイルのリストを簡単にスキャンして、一致を簡単に見つけることができます。

Windowsでは、次のように同じことができます。

for /R %j in (*.jar) do @echo %j & @jar tf %j | findstr IObservableList

Windowsでは、コマンドセパレータは「;」ではなく「&」であることに注意してください。また、 '@'はコマンドのエコーを抑制して、上記のlinux findの出力と同じように整然とした出力を提供します。ただしfindstr、一致した文字列を太字にしないため、一致したクラス名を表示するには、出力を少し詳しく確認する必要があります。ウィンドウの「for」コマンドは、テキストファイルのループなど、かなりの数のトリックを知っていることがわかります...

楽しい


2

文字列シェルコマンド(sh -c)を実行すると、次のように最もうまく機能することがわかりました。

find -name 'file_*' -follow -type f -exec bash -c "zcat \"{}\" | agrep -dEOE 'grep'" \;

0

単純な代替手段を探している場合、これはループを使用して行うことができます。

for i in $(find -name 'file_*' -follow -type f);do zcat $i | agrep -dEOE 'grep');done

または、より一般的で理解しやすい形式:

for i in $(YOUR_FIND_COMMAND);do YOUR_EXEC_COMMAND_AND_PIPES );done

YOUR_EXEC_COMMAND_AND_PIPESの{}を$ iに置き換えます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.