私はたくさんのgzファイルを持っていて、それらの解凍されたバージョンにはパターンA
とB=1
が含まれています(これらは確かにA
が最初に現れる別の行にあります)。
A
が存在し、B=1
が存在する行の内容を表示するコマンドを記述したいと思います。または、少なくともA
とB=1
の間のコンテンツを含みます。
入力ファイル1:
..A ...
...
...B=0..
...
入力ファイル2:
..A ...
...
...B=1..
...
私のコマンドは必須出力A ....B=1
for file2およびnothing file1。
私はこのようなことをしましたが、期待どおりに機能していません:
find . -name \*.gz -print0 | xargs -0 zcat | sed -n -e '/A/,/B=1/p'
ここの問題は何ですか?
ここでは、圧縮を無視します。 A
とB=1
の間の行を出力したいが、両方が表示された場合のみ。 sed
が表示されるとすぐに出力を開始し、B=1
をチェックしないため、使用したA
はそれを行いません。 sed
のホールドバッファーを使用して、B=1
が見つかるまですべてを保持することができますが、awk
の方が使いやすいので、次のようにします。
$ echo -en 'not this\nA\nthis\nB=1\nnot this\n' |
awk '/A/ {save=1} save {data = data $0 ORS} /B=0/ {save=0; data=""} /B=1/ {save=0; printf "%s", data; data=""} '
A
this
B=1
B=0
ルールは、印刷されるべきではないブロックを処理します。
次に、圧縮と複数のファイルを処理します。 find
+ xargs
は機能しましたが、一部のファイルに部分的なブロックが含まれる場合(A
にB
がない場合)、ファイルを連結すると問題が発生します。そうでないと仮定すると、awkを最後に固定できます。
$ find . -name foo\*.gz -print0 | xargs -0 zcat | \
awk '/A/ {s=1} s {d = d $0 ORS} /B=0/ {s=0; d=""}
/B=1/ {s=0; printf "%s", d; d=""} '
部分的なブロックを処理する必要がある場合は、各ファイルを個別に処理する必要があります。
$ find . -name foo\*.gz -print0 | xargs -0 sh -c '
for f; do zcat "$f" | awk '\''/A/ {s=1} s {d = d $0 ORS}
/B=0/ {s=0; d=""} /B=1/ {s=0; printf "%s", d; d=""} '\''; done' sh
引用は恐ろしいので、awk
スクリプトはおそらく独自のファイルにする必要があります。
または、シェル(Bash/ksh/zsh)で実行するだけです。
$ shopt -s globstar # set -o globstar in ksh
$ for f in **/*.gz ; do zcat "$f" |
awk '/A/ {s=1} s {d = d $0 ORS} /B=0/ {s=0; d=""}
/B=1/ {s=0; printf "%s", d; d=""} ' ; done
(A
およびB=1
行ではなく)介在する行のみを印刷する場合は、/A/ {...}
および/B=.../ {...}
ブロックの位置を交換します。
確かに最善の方法ではありませんが、それは私にとってはうまくいきます:
find -name "*.gz" | xargs zgrep -l A | xargs zgrep -l "B=1" | xargs zcat | sed -n '/A/,/B=1/p
最初にファイルのリストを取得し、次にAを含むファイルをフィルター処理し、次にB = 1を含むファイルをフィルター処理します。結果のファイルはzcat
からsed
です。
危険:1つのファイルにB = 1とAの両方がこの順序で含まれている場合、そのファイルの内容が最後に書き込まれます。
例:
$ ls /tmp/file*gz
/tmp/filea.gz /tmp/fileb.gz
$ zcat /tmp/filea.gz
one
two
three
A
four five
six
B=1
seven
eight
nine
$ zcat /tmp/fileb.gz
one
two
three
A
four five
six
B=0
seven
eight
nine
$ find /tmp -type f -name "file*.gz" | xargs zgrep -l A | xargs zgrep -l "B=1" | xargs zcat | sed -n '/A/,/B=1/p'
A
four five
six
B=1
pcregrep
があり、それがlibzサポート付きでビルドされている場合、次のことができます。
pcregrep --include='\.gz$' -rM '(?s)A.*?B=1' .
例:
$ pcregrep --help | grep zlib
Files whose names end in .gz are read using zlib.
Files whose names end in .bz2 are read using bzlib2.
$ pcregrep --include='\.gz$' -rM '(?s)A.*?B=1' .
./1/2/3/x.gz:AAA
blih
BOB=123
./b.gz:A
blah
B=1
zcat *.gz | \
sed 's/B=[0-9].*/&\x00/' | \
grep -zo 'A.*B=1' | \
sed 's/\x00/\n=====\n/'