나는 많은 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
때문에 그렇게 하지 않습니다 . 우리는 그것이 발견될 때까지 모든 것을 보관하기 위해 홀딩 버퍼를 사용할 수 있지만 저는 그것이 더 편합니다 . 그래서 여기 있습니다:A
B=1
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=.../ {...}
답변2
물론 최선의 접근 방식은 아니지만 저에게는 효과적이었습니다.
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
.
위험: 파일에 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
가지고 있고 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
답변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을 보다 명확한 구분 기호로 변환합니다.