다음과 같은 섹션이 포함된 거대한 파일을 생성 중입니다.
~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~ Gradients ~~~~~~~~
~~~~~~~~~ x y z ~~~~~~~~~~
~ ~
~ H 1 0.00781 0.00108 0.00038 ~
~ H 2 0.01271 -0.01507 0.02839 ~
~ C 1 -0.05015 -0.01803 0.01588 ~
~ O 1 0.01733 0.03089 -0.04611 ~
~ O 2 0.01230 0.00114 0.00147 ~
~ ~
~~~~~~~~~~~~~~~~~~~~~~~~
다음 숫자(xyz)를 추출해야 합니다.
0.00781 0.00108 0.00038
0.01271 -0.01507 0.02839
-0.05015 -0.01803 0.01588
0.01733 0.03089 -0.04611
0.01230 0.00114 0.00147
나는 다음 스크립트를 작성했습니다.
awk '/z ~/ {for(i=1; i<=6; i++) {getline; print $4, $5, $6}}' filename
하지만 "~~" 줄 때문에 빈 줄이 나옵니다.
즉, /z ~/
패턴이 발견될 때마다 다른 줄(패턴+1)을 건너뛰고 다른 다섯 줄(패턴+2+3+4+5+6)의 내용만 인쇄하고 싶습니다. 물론 반복(수십만 번)이 필요합니다.
답변1
앗해결책:
awk '/z ~/{ n=NR+2 }n && n<=NR && NR<(n+5){ print $4,$5,$6 }' file | column -t
산출:
0.00781 0.00108 0.00038
0.01271 -0.01507 0.02839
-0.05015 -0.01803 0.01588
0.01733 0.03089 -0.04611
0.01230 0.00114 0.00147
NR
- 현재 레코드 수n=NR+2
-n
모델 라인 뒤의 "시작" 라인 번호를 나타냅니다.
답변2
가장 간단한 해결책은 하나를 더 추가 getline
하고 6행 대신 5행을 얻는 것입니다.
$ awk '/z ~/ {getline;for(i=1; i<=5; i++) {getline; print $4, $5, $6}}' file
0.00781 0.00108 0.00038
0.01271 -0.01507 0.02839
-0.05015 -0.01803 0.01588
0.01733 0.03089 -0.04611
0.01230 0.00114 0.00147
하지만 개인적으로 저는 약간 다른 방식으로 작업을 수행하겠습니다.
$ awk '/z ~/{f=2;} /~ ~/{f--}; (f==1 && NF>5){print $4, $5, $6} ' file
0.00781 0.00108 0.00038
0.01271 -0.01507 0.02839
-0.05015 -0.01803 0.01588
0.01733 0.03089 -0.04611
0.01230 0.00114 0.00147
여기서의 아이디어는 일치하는 줄에 플래그(변수)를 설정 f
하고 일치하는 줄을 찾을 때마다 해당 값을 1씩 감소시키는 것입니다. 그런 다음 필드 4, 5, 6을 다음 줄에만 인쇄합니다.2
z ~
~ ~
f
1
그리고필드가 5개 이상 있습니다.
두 예 모두 예쁜 인쇄를 얻으려면 다음을 사용 -vOFS="\t"
하거나 더 나은 방법을 사용할 수 있습니다 printf
.
$ awk '/z ~/{f=2;} /~ ~/{f--}; (f==1 && NF>5){printf "%10s%10s%10s\n", $4, $5, $6} ' file
0.00781 0.00108 0.00038
0.01271 -0.01507 0.02839
-0.05015 -0.01803 0.01588
0.01733 0.03089 -0.04611
0.01230 0.00114 0.00147
답변3
피복재
- 먼저 범위를 선으로 분리합니다
/~ ~/
. 외부의 모든 내용은 삭제됩니다. - 범위 이상값 자체도 제거됩니다.
- 이제 처리할 올바른 라인이 생겼습니다. 이 라인에서 우리는
\n
네 번째 필드의 시작 부분에 마커를 배치하고 여섯 번째 필드의 끝에 또 다른 마커를 배치합니다. - 마지막으로 이러한 태그 외부의 모든 항목을 제거하여 네 번째, 다섯 번째, 여섯 번째 필드와 이들 사이의 공백(수정되지 않음)만 남깁니다.
sed -ne '
/~ ~/,//!d
//d
s/[^[:space:]]\{1,\}/&\n/6
s/[^[:space:]]\{1,\}/\n&/4
s/.*\n\(.*\)\n.*/\1/p
' yourfile
결과
0.00781 0.00108 0.00038
0.01271 -0.01507 0.02839
-0.05015 -0.01803 0.01588
0.01733 0.03089 -0.04611
0.01230 0.00114 0.00147
답변4
이 라인을 일치시키는 것에 관한 한 /^~ [A-Z]/
패턴은 충분하며 각 인쇄에 대해 해당 필드 4, 5 및 6이 있습니다.
awk 버전은 다음과 같습니다.
$ awk '/^~ [A-Z]/{printf("%-8s\t%-8s\t%-8s\n",$4,$5,$6)}' input.txt
0.00781 0.00108 0.00038
0.01271 -0.01507 0.02839
-0.05015 -0.01803 0.01588
0.01733 0.03089 -0.04611
0.01230 0.00114 0.00147
그리고 같은 내용을 Perl로 번역하면 다음과 같습니다.
$ perl -ane 'printf("%-8s\t%-8s\t%-8s\n",$F[3],$F[4],$F[5]) if /^~ [A-Z]/' input.txt
0.00781 0.00108 0.00038
0.01271 -0.01507 0.02839
-0.05015 -0.01803 0.01588
0.01733 0.03089 -0.04611
0.01230 0.00114 0.00147
여기서는 적절한 형식화를 위해 printf()
왼쪽 정렬 플래그와 함께 함수를 사용합니다 %-8s
.
또 다른 접근 방식은 필요한 숫자를 부동 소수점 숫자로 처리하고 %f
대신 지정자를 사용하는 것입니다 %-8s
. 그러나 이렇게 하면 일부 숫자에 추가 0이 추가됩니다.