findコマンドによって返されたファイルのリストをcatにパイプしてすべてのファイルを表示する方法


204

私はやっていて、findファイルのリストを取得しています。cat(catがすべてのファイルの内容を表示するように)それを別のユーティリティにパイプして、基本的にgrepこれらのファイルから何かを必要とする方法を教えてください。

回答:


340
  1. 別のプロセスへのパイピング(これはあなたがやろうとしていることをあなたが言ったことを達成することはできませんが):

    command1 | command2
    

    これにより、command1の出力がcommand2の入力として送信されます。

  2. -exec上でfind(これは、あなたがやりたいと思っている何だろう-しかし、固有のものですfind

    find . -name '*.foo' -exec cat {} \;
    

    (すべては間find-exec、あなたが既に使用していた検索述語がある。 {}あなたは、コマンドの中に見つかった特定のファイル(代用しますcat {}この場合は)、\;終了している-execコマンドを使用します。)

  3. あるプロセスの出力をコマンドライン引数として別のプロセスに送信する

    command2 `command1`
    

    例えば:

    cat `find . -name '*.foo' -print`
    

    (これらは通常の引用符ではなく、バッククォートであることに注意してください(キーボードのチルダ〜の下))これにより、の出力がコマンドライン引数として送信command1command2れます。ただし、スペースを含むファイル名(改行など)は個別の引数に分割されます。


2
find -name '*.foo' -printは私のために素晴らしく働きました...ありがとう
デバン・カムダー

逆引用符はうまく機能し、より一般化されています。これを使用して、ファイルからファイルのリストをcatすることもできます。
Hazok

11
の最新バージョンではfind、次のように記述できることに注意してください。はfind . -name '*.foo' -exec cat {} +、が便利なだけのファイル名を1つのコマンド呼び出しにグループ化する+ことを示していfindます。これは非常に便利です(-print0andに頼らずにファイル名のスペースなどを扱いますxargs -0)。
ジョナサンレフラー、

18
言及なし:find . -name '*.foo' | xargs cat
stewSquared

3
ただ、@stewSquaredの答えに追加するには:行う、特定の文字列を含むファイル内のすべての行を検索するにfind . -name '*.foo' | xargs cat | grep string
ビム

84

最新バージョン

POSIX 2008は+マーカーを追加しました。findこれは、適切な数のファイルを単一のコマンド実行に自動的にグループ化することを意味しますxargs

  1. ファイル名の奇妙な文字を気にする必要はありません。
  2. コマンドがファイル名なしで呼び出されることを心配する必要はありません。

ファイル名の問題はオプションがxargsない-0場合の問題であり、「ファイル名が0でも実行」の問題はオプションがある場合とない場合の問題ですが、-0GNU xargsには-rorの--no-run-if-emptyオプションがあり、これを防ぐことができます。また、この表記はプロセス数を削減するものであり、パフォーマンスの違いを測定する可能性が高いわけではありません。したがって、あなたは賢明に書くことができます:

find . -exec grep something {} +

クラシックバージョン

find . -print | xargs grep something

Linuxを使用している場合、またはGNU findxargsコマンドを使用-print0している場合は、with findおよび-0with xargsを使用して、スペースやその他の奇妙な文字を含むファイル名を処理します。

find . -print0 | xargs -0 grep something

からの結果の微調整 grep

ファイル名(テキストのみ)が必要ない場合は、適切なオプションをgrep(通常は-h「見出し」を抑制するために)追加します。によってファイル名が確実に出力されるようにするにはgrep(ファイルが1つしか見つからない場合、またはの最後の呼び出しでgrepファイル名が1つしか与えられない場合でも)、コマンドラインに追加/dev/nullして、xargs常に少なくとも2つのファイル名が存在するようにします。


私のように混乱している人のために、この方法は最初にfindのすべての出力を提供し、次にの出力を提供することに注意してくださいxargs grep something
Eric Hu

3
@EricHu:私はあなたが混乱しているのを見ることができますが、少なくとも私が知っているどのUnixベースのシステムでも、あなたが言うことを実行しません。の出力はfind、の標準入力にパイプされますxargsxargsプログラムは、ホワイトスペース(空白、改行、タブなど)で、標準入力、分割入力を読み取り、コマンドに単語の数を追加grep somethingし、コマンドラインを実行します。xargs次に、入力を読み取り、入力がなくなるまでコマンドを実行し続けます。xargs指定さgrepれた入力に対して必要なだけコマンドを実行します(findこの例では)。
ジョナサンレフラー2013

私の間違い、これは、grepを使用して、一致した各ファイル内を検索することです。私は単にfindの出力をgrepでフィルタリングすることを探していました
Eric Hu

1
エラーは、正常に動作するすべてのコマンドで標準エラー(ファイル記述子2)に送られます。stderrをリダイレクトし/dev/nullてエラーメッセージを失います。
ジョナサンレフラー2013

1
これには、ファイルパスにスペースが含まれているとうまく機能するという利点もあります。""-> "\"を 'sed'しても、 `でそれを壊しますが、xargsで完全に機能します
JZL003

36

findコマンドから返されたファイルのリストをコマンドに渡す方法はいくつかありますが、cat技術的にはすべてがパイピングを使用するわけではなく、実際に直接にパイピングするものはありませんcat

  1. 最も簡単なのは、バックティック(`)を使用することです。

    cat `find [whatever]`
    

    これにより、の出力がfind取得され、事実上のコマンドラインに配置されcatます。find出力が多すぎる(コマンドラインに収まりきらない)場合、または出力に特殊文字(スペースなど)が含まれる場合、これはうまく機能しません。

  2. を含む一部のシェルではbash$()バックティックの代わりに使用できます。

    cat $(find [whatever])
    

    これは移植性は低くなりますが、ネスト可能です。それを除けば、バックティックとほとんど同じ警告があります。

  3. 見つかったものに対して他のコマンドを実行することはの一般的な使用方法であるためfind、findには、-exec見つかったファイルごとにコマンドを実行するアクションがあります。

    find [whatever] -exec cat {} \;
    

    {}ファイル名のプレースホルダで、\;マークコマンドの終わり(これは、後に他のアクションを持つことが可能です-exec。)

    これは、複数のファイル名を渡すcat単一のインスタンスを実行するのではなく、すべてのファイルに対して1回実行されcatます。これは非効率的であり、一部のコマンドに対して希望する動作をしない場合があります(は問題ありませんcat)。構文もタイプするのが面倒です-セミコロンはシェルにとって特別なので、セミコロンをエスケープする必要があります!

  4. の一部のバージョンfind(特にGNUバージョン)では、を置き換え;+-execの追加モードを使用して、以下のインスタンスを実行しますcat

    find [whatever] -exec cat {} +
    

    これによりcat、の呼び出しごとに複数のファイル名が渡されるため、より効率的です。

    ただし、これは単一の呼び出しの使用を保証するものではないことに注意してください。コマンドラインが長すぎる場合、引数はの複数の呼び出しに分散されますcat。以下のためにcat、このおそらく大したことではないですが、いくつかの他のコマンドのために、これは望ましくない方法で動作を変更することがあります。Linuxシステムでは、コマンドラインの長さの制限が非常に大きいため、他の一部のOSと比較して、複数の呼び出しに分割することは非常にまれです。

  5. 古典的/ポータブルなアプローチは以下を使用することxargsです:

    find [whatever] | xargs cat
    

    xargs指定されたコマンド(catこの場合は)を実行し、標準入力から読み取った内容に基づいて引数を追加します。と同様-exec+、必要に応じてコマンドラインを分割します。つまり、find出力が多すぎると、cat複数回実行されます。前述のセクションで述べたように、-execこの分割により異なる動作が発生する可能性のあるコマンドがいくつかあります。xargsこのようにxargs使用すると、空白を区切り文字として使用するだけなので、ファイル名のスペースに問題が発生することに注意してください。

  6. 最も堅牢で、移植性があり、効率的な方法でも使用しますxargs

    find [whatever] -print0 | xargs -0 cat
    

    -print0フラグが伝えfind使用する\0(ヌル文字)をファイル名の間の区切り文字を、そして-0フラグが伝えxargsこれらの期待する\0区切り文字を。これは-exec...の+アプローチとほとんど同じ動作をしますが、移植性は高くなります(ただし、残念ながら詳細度は高くなります)。


backtickメソッドは、などの他のコマンドlsでも機能するため、優れています。
マーティンブラウン

@Martin Braun using $()また、以外のコマンドでも機能しますfind
ローレンスゴンサルベス

おかげで、私はスペースなどの特殊文字を扱っていないので、必要に応じて、(1)の後で読みをやめました。
マーティンブラウン

9

これを達成するには(bashを使用)、次のようにします。

cat $(find . -name '*.foo')

これは「コマンド置換」と呼ばれ、デフォルトでラインフィードを取り除きます。これは非常に便利です。

詳細はこちら


6

私にはシェルスクリプトの仕事のように聞こえます:

for file in 'find -name *.xml'
do
   grep 'hello' file
done

またはそのようなもの


2
これは、必ずしも最適ではありませんが、質問に対する有効な回答です。
ジョナサンレフラー、

1
...そうですが、ファイル名がリストされた1つの大きなファイルが必要な場合にも最適です。
ʍǝɥʇɐɯ

1
私はこれが一番好きです。このようなループブロックは、他のことを実行する余地を残します。
kakyo

4

ここに、私が興味のあるコンテンツを含むファイル名を見つける方法があります。ファイル名のスペースもうまく処理する1つのbash行だけです。

find . -name \*.xml | while read i; do grep '<?xml' "$i" >/dev/null; [ $? == 0 ] && echo $i; done

3

私はこのようなものを使用します:

find . -name <filename> -print0 | xargs -0 cat | grep <word2search4>

-print0find」の「-0」引数と「xargs」の「」引数は、ファイルのパス/名前の空白を正しく処理するために必要です。



2

これが一般的な使用のための私のショットです:

grep YOURSTRING `find .`

ファイル名を出力します


2

bashでは、以下が適切です。

find /dir -type f -print0 | xargs -0i cat {} | grep whatever

これにより、/dirディレクトリ内のすべてのファイルが検索されxargs、安全にファイル名がにパイプされます。grepます。

xargs何千ものファイルがある場合、スキップはお勧めできません/dircat引数リストが長すぎるために壊れます。xargsそれをすべて整理してくれます。

スペースを含むファイル名を適切に処理するための-print0引数とfindメッシュするための-0引数xargs-i引数は、xargsあなたが必要なファイル名を挿入することができますcatコマンドラインを。大括弧は、catからコマンドにパイプされたファイル名に置き換えられますfind



0

ggrepを使用します

ggrep -H -R -I "mysearchstring" *

現在のディレクトリまたはサブディレクトリにあるテキストを含むUNIXのファイルを検索するには


0

これにより、ファイルの名前と内容のみが再帰的に出力されます。

find . -type f -printf '\n\n%p:\n' -exec cat {} \;

編集(改良版): これはテキスト(ASCII)ファイルの名前と内容を再帰的にのみ印刷します。

find . -type f -exec grep -Iq . {} \; -print | xargs awk 'FNR==1{print FILENAME ":" $0; }'

もう1つの試み

find . -type f -exec grep -Iq . {} \; -printf "\n%p:" -exec cat {} \;


-1

ディレクトリ/ ghiおよび/ jklにあるサーバー上のすべてのabc.defファイルの内容をリストおよび表示するには

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec ls {} \; -exec cat {} \;

コメント付きのエントリを持つabc.defファイルをリストして表示するには、ディレクトリ/ ghiおよび/ jkl内のそれらのエントリを参照してください。

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec grep -H ^# {} \;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.