複数のファイルから最後の一致を取得するには、Grepとfindを使用してください。

複数のファイルから最後の一致を取得するには、Grepとfindを使用してください。

両方のファイルに次の内容があるとします。

$ cat ttest1.txt 
x = 1
x = 3
y = 5
$ cat ttest2.txt 
x = 4
x = 10
y = 3

xファイルを再帰的にgrepし、各ファイルの最後のインスタンスを印刷したいと思います。したがって、希望の出力は次のようになります。

ttest1.txt:x = 3
ttest2.txt:x = 10

次のgrep組み合わせはtail1つのファイルに対しては機能しますが、複数のファイルでは機能しません。

$ grep x ttest1.txt 
x = 1
x = 3
$ grep x ttest1.txt | tail -n 1
x = 3
$ grep -r x ttest* | tail -n 1
ttest2.txt:x = 10

この問題をどのように解決できますか?

答え1

するとき

grep -r x ttest* 

あなたはストリームを得る

ttest1.txt:x = 1
ttest1.txt:x = 3
ttest2.txt:x = 4
ttest2.txt:x = 10

これは予想通りtail -1ですttest2.txt:x = 10

grep | tailただし、マージされたストリームではなく、個々のファイルごとに結合を実行したいと思います。したがって、個々のファイルごとにこれを実行してください。

for f in ttest* ; do
    grep x "$f" | tail -n 1
done

答え2

を使用すると、awk正規表現文字列を使用できます(参照:動的正規表現)、各入力ファイルの最後の一致を覚えて印刷します。

$ awk -v regex="x" 'FNR==1 && m!=""{print m;m=""} 
        $0 ~ regex{m=FILENAME ":" $0}
        END{if (m!="")print m}' ttest*
ttest1.txt:x = 3
ttest2.txt:x = 10

以下と再帰的に結合されますfind

$ find . -name 'ttest*' -type f -exec awk -v regex="x" '
        FNR==1 && m!=""{print m;m=""}
        $0 ~ regex{m=FILENAME ":" $0}
        END{if (m!="")print m}' {} +
./ttest1.txt:x = 3
./ttest2.txt:x = 10

答え3

GNU sedの使用:

sed -sn '/x/h; $ { x; F; p; }' ttest*

出力:

ttest1.txt
x = 3
ttest2.txt
x = 10

paste -d: - -結果を1行に表示するには、このオプションを渡してください。 -changeコマンドxの後にチェックが含まれていないファイルから出力したくない場合は、x次のようにします。{ x; /./ { F; p; z; }; }

答え4

1つの方法は次のとおりです。

grep  x <yourpath>*  | tac | awk  'BEGIN{FS=":"};seen!=$1{print $0;seen=$1}'

tac は awk ジョブを準備するために grep 結果を反転し、各ファイルから最初の一致のみを印刷します。

関連情報