grepコマンドの結果として受け取った各行を処理する方法


152

次のようにgrepコマンドを実行した後、ファイルからいくつかの行を取得しました。

var=`grep xyz abc.txt`

結果として、xyzで構成される10行を得たとしましょう。

次に、grepコマンドの結果として取得した各行を処理する必要があります。これをどのように進めますか?


6
ここでの答えはどれも、grep -oこの種のものの力について言及していません。-oフラグはお返ししますのみ出力の1行に1つの試合で、テキストと一致します。(網羅的ではないため、echo aaa |grep 'a*'「aaa」のみを提供し、3つの部分一致「」、「a」、および「aa」を省略します)
Adam Katz

回答:


269

簡単な方法の1つは、出力を変数に保存するのではなく、while / readループで直接反復することです。

何かのようなもの:

grep xyz abc.txt | while read -r line ; do
    echo "Processing $line"
    # your code goes here
done

あなたが何を求めているかに応じて、このスキームにはバリエーションがあります。

ループ内で変数を変更する必要がある場合(およびその変更がループの外で見えるようにする場合)、fedorquiの回答に記載されているように、プロセス置換を使用できます。

while read -r line ; do
    echo "Processing $line"
    # your code goes here
done < <(grep xyz abc.txt)

xyzの行がない場合?
XYZ_Linux

その後、何も起こりません、ループは実行されません。
マット2013年

13
この方法の問題は、(パイプのため)ループ内のすべてがサブシェルにあるため、ループ中にループの外側で定義された変数を設定しても、ループの後でそれらの値を使用できないことです!
David Doria、

3
@David:懸念に対処するための代替手段を提供しました。(fedorquiもすでに対応しています。)
Mat

出力の最後の行が改行で終了していないコマンドの場合、while read p || [[ -n $p ]]; do ...stackoverflow.com/questions/1521462/…から借用)
Ohad Schneider

21

次のwhile readループを実行できます。grepこれは、いわゆるプロセス置換を使用してコマンドの結果によって供給されます。

while IFS= read -r result
do
    #whatever with value $result
done < <(grep "xyz" abc.txt)

このようにして、結果を変数に格納する必要はありませんが、その出力をループに直接「注入」します。


使用を注意IFS=してread -rBashFAQ / 001の推奨事項に従って:私はファイル(データ・ストリーム、変数)をライン・バイ・ライン(および/またはフィールドごと)読むことができますどのように?

読み取る-rオプションは、バックスラッシュの解釈を防止します(通常、バックスラッシュの改行ペアとして使用され、複数行にわたって継続するか、区切り文字をエスケープします)。このオプションがないと、入力のエスケープされていないバックスラッシュは破棄されます。ほとんどの場合、-rオプションをreadとともに使用する必要があります。

上記のシナリオでは、IFS =は先頭と末尾の空白のトリミングを防止します。この効果が必要な場合は削除してください。

プロセスの置換については、bashハッカーのページで説明されています

プロセス置換は、プロセスの入力または出力(コマンドのシーケンス)が一時ファイルとして表示されるリダイレクトの形式です。


はい、forバージョンをストライキしました。stackoverflow.com/a/14588210/1983854の"${$(grep xyz abc.txt)[@]}"ようにループを実行しようとしましたが、できませんでした。最初のバージョンはそのままにしておきます。
fedorqui 'SO stop harming' 2013

1
コマンド置換にパラメーター拡張を適用することはできません(zshそのようなネストがおそらく機能するを使用している場合を除きます)。
chepner 2013年

このイディオムで考えられる1つの問題は、ループ内の何かが標準入力から読み取ろうとすると、ファイルの一部が取得されることです。この可能性を回避するために、私はstdinではなくファイル記述子3を介してファイルを送信することを好みます。ただ、使用while IFS= read -r result <&3およびdone 3< <(grep ...
ゴードンDavisson


2

--line-buffered grepオプションを使用して反復なし:

your_command | grep --line-buffered "your search"

すべての「api」関連ルートをgrepするためのSymfony PHPフレームワークルーターデバッグコマンド出力を使用した実際の例:

php bin/console d:r | grep --line-buffered "api"

your_commandが長時間実行さtail -f some.logれている場合(私の場合、など)に機能する唯一のソリューション...
Izkata

0

多くの場合、処理の順序は重要ではありません。GNU Parallelはこの状況のた​​めに作られています:

grep xyz abc.txt | parallel echo do stuff to {}

あなたが処理するのがより似ている場合:

grep xyz abc.txt | myprogram_reading_from_stdin

そしてmyprogram遅いとあなたは走ることができます:

grep xyz abc.txt | parallel --pipe myprogram_reading_from_stdin

0

while / readループでgrep結果を反復処理します。お気に入り:

grep pattern filename.txt | while read -r line ; do
    echo "Matched Line:  $line"
    # your code goes here
done

0

ワンライナーをお探しの方:

grep xyz abc.txt | while read -r line; do echo "Processing $line"; done
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.