gzip ファイル用 Sed

gzip ファイル用 Sed

私は多くのgzファイルを持っており、解凍したバージョンにはパターンが含まれていますAB=1(これらは明らかにA最初に出てくる別の行にあります。)

A現在行とB=1現在行の内容を提供するコマンドを作成したいと思います。または少なくともAその間に何かがありますB=1

入力ファイル1:

..A ...
...
...B=0..
...

入力ファイル2:

..A ...
...
...B=1..
...

私のコマンドは必ずfile2の出力A ....B=1何もないファイル1の場合。

同様のことをしましたが、期待どおりに動作しませんでした。

find . -name \*.gz -print0 | xargs -0 zcat | sed -n -e '/A/,/B=1/p'

ここで問題は何ですか?

答え1

今は圧縮を無視してみましょう。Aとの間の行を出力しようとしていますB=1が、両方が存在する場合にのみ可能です。あなたが使用しているのはそれを見るとすぐに出力を開始して確認しないので、そうしませんsed。私たちはそれが見つかるまですべてを保持するために保持バッファを使用できますが、私はそれがより快適です。だからここにあります:AB=1sedB=1awk

$ 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=.../ {...}

答え2

もちろん、最善のアプローチではありませんが、私にとっては効果的でした。

find -name "*.gz" | xargs zgrep -l A | xargs zgrep -l "B=1" | xargs zcat | sed -n '/A/,/B=1/p

最初にファイルのリストを取得し、Aを含むファイルをフィルタリングし、次にB = 1を含むファイルをフィルタリングすると、結果ファイルzcatsed.

危険:ファイルに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

答え3

持っていて、pcregreplibzサポートで構築されている場合は、次のことができます。

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

答え4

zcat *.gz | \
sed  's/B=[0-9].*/&\x00/'  | \
grep  -zo 'A.*B=1' | \
sed 's/\x00/\n=====\n/'
  • 行1(findコマンドで置き換え可能)
  • 2行目では、 "B = ..."行の後にnullを追加してレジスタを明示的に区切ります。
  • 行3は、ヌルで区切られたレジスタシーケンス、A ... B = 1パターンをgrepします。
  • 行4(有用な場合)は、nullをより明確な区切り文字に変換します。

関連情報