AWK 문제: 주어진 /pattern/ 다음의 세 번째 줄부터 시작하여 N 줄을 인쇄합니다.

AWK 문제: 주어진 /pattern/ 다음의 세 번째 줄부터 시작하여 N 줄을 인쇄합니다.

다음과 같은 섹션이 포함된 거대한 파일을 생성 중입니다.

~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~ 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을 다음 줄에만 인쇄합니다.2z ~~ ~f1 그리고필드가 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

피복재

  1. 먼저 범위를 선으로 분리합니다 /~ ~/. 외부의 모든 내용은 삭제됩니다.
  2. 범위 이상값 자체도 제거됩니다.
  3. 이제 처리할 올바른 라인이 생겼습니다. 이 라인에서 우리는 \n네 번째 필드의 시작 부분에 마커를 배치하고 여섯 번째 필드의 끝에 또 다른 마커를 배치합니다.
  4. 마지막으로 이러한 태그 외부의 모든 항목을 제거하여 네 번째, 다섯 번째, 여섯 번째 필드와 이들 사이의 공백(수정되지 않음)만 남깁니다.

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이 추가됩니다.

관련 정보