awk를 사용하여 비율 계산

awk를 사용하여 비율 계산
awk 'NR==1{$4="ratio"}NR>1{$4 = ($3)/($2)} {print $1 "\t" $2 "\t" $3 "\t" $4}' A  B

awk: 명령. 줄: 1: (FILENAME=A FNR=18) 치명적: 0으로 나누기를 시도했습니다.

이 오류를 해결하는 데 도움을 줄 수 있는 사람이 있나요?

NR==1여기서 합계는 무엇을 NR>1의미하나요? 그것은 이상한 예에 있습니다. 나는 그것을 이해하지 못합니다. NR이 레코드 번호인 것은 알지만 여기서는 왜 사용합니까?

답변1

예제 작성자는 파일 A와 B를 다음 형식으로 상상한 것 같습니다.

파일 A:

X Y Z
1 2 3
4 5 6

파일 B:

6 7 8
o o 0

AWK 예제에서는 네 번째 열을 생성합니다. 여기서 NR은 현재 AWK에서 처리 중인 행을 나타냅니다. 첫 번째 줄에서는 네 번째 인수를 문자열 "ratio"(열 이름)로 설정하고, 모든 후속 줄에서는 네 번째 인수를 두 번째 인수로 나눈 세 번째 인수로 설정합니다. 결과:

awk 'NR==1{$4="ratio"}NR>1{$4 = ($3)/($2)} {print $1 "\t" $2 "\t" $3 "\t" $4}' A
X   Y   Z   ratio
1   2   3   1.5
4   5   6   1.2
6   7   8   1.14286
1   2   3   1.5

발생한 오류는 다음과 같습니다.

awk: 명령. 줄: 1: (FILENAME=A FNR=18) 치명적: 0으로 나누기를 시도했습니다.

파일 A의 18행에 2열과 3열의 숫자가 포함되어 있는지 확인하세요.

sed를 사용하여 'o' 문자를 0으로 변환할 수 있습니다.

cat A B | sed 's/\bo\b/0/g'

열 2가 0인지 확인하고 그에 따라 조치를 취할 수 있습니다.

awk 'NR==1{$4="ratio"}NR>1{if($2==0) $4 = "N/A"; else $4 = ($3)/($2)}

합치면 다음과 같은 이점을 얻을 수 있습니다.

cat A B | sed 's/\bo\b/0/g' | awk 'NR==1{$4="ratio"}NR>1{if($2==0) $4 = "N/A"; else $4 = ($3)/($2)} {print $1 "\t" $2 "\t" $3 "\t" $4}'
X   Y   Z   ratio
1   2   3   1.5
4   5   6   1.2
6   7   8   1.14286
0   0   0   N/A

답변2

주어진 예에서,

awk 'NR==1{$4="ratio"}NR>1{$4 = ($3)/($2)} {print $1 "\t" $2 "\t" $3 "\t" $4}' A  B

NR지금까지 읽은 레코드 수입니다. 다음과 같은 예에서 이를 사용하여 다음과 같이 테이블 헤더를 건너뛸 수 있습니다.

Date        Cost     Quantity
2016/04/10  12.57    3
2016/04/19  11.74    2

왜냐하면 "비용"을 "수량"(숫자가 아님)으로 나눌 수 없기 때문입니다.

그건 그렇고, 당신의 데이터할 수 있다4개 이상의 열이 있습니다. 그러나 awk를 사용하면 입력 데이터에 없는 열에 할당할 수 있습니다. 따라서 처음에는 $4="ratio"기존 열을 변경하는 것일 수도 있지만 연속 레코드에 대한 계산을 반영하기 위해 데이터에 열을 추가하는 것일 가능성이 높습니다.

오류(0으로 나누기)의 해석은 다른 질문입니다 NR. 숫자 데이터가 있는지 확인 $2하고 $3패턴을 사용할 수 있습니다. 예를 들어 다음 확인을 추가하세요.

다음과 같은 것을 생산합니다

#!/bin/sh
awk 'function isnum(v) { 
     if ( v ~ /^[0-9.]+$/ ) 
         return 1; 
     else 
         return 0; 
     } 
     (NR==1){$4="ratio"} 
     (NR>1 && NF >= 3 && isnum($2) && isnum($3) && $3 > 0){$4 = ($3)/($2)} 
     {print $1 "\t" $2 "\t" $3 "\t" $4}' A  B

isnum함수는 단순화되었지만 부호 없는 소수를 허용합니다.

한 줄 스크립트를 선호한다면 awk 스크립트는 자유 형식이라는 점을 기억하세요. 그래서... 이렇게 할 수 있습니다:

awk 'function isnum(v){if(v~/^[0-9.]+$/)return 1;else return 0;}(NR==1){$4="ratio"}(NR>1&&NF>=3&&isnum($2)&&isnum($3)&&$3>0){$4=($3)/($2)}{print $1"\t"$2"\t"$3"\t"$4}' A  B

관련 정보