gzip 파일용 Sed

gzip 파일용 Sed

나는 많은 gz 파일을 가지고 있으며 압축을 푼 버전에는 패턴이 포함되어 있습니다 A. B=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을 보다 명확한 구분 기호로 변환합니다.

관련 정보