파일의 열을 합산하는 프로그램이 있습니다.
awk -v col=2 '{sum+=$col}END{print sum}' input-file
그러나 여기에는 문제가 있습니다. 숫자 데이터가 없거나 숫자가 누락된 파일을 제공하면 이를 0으로 해석합니다.
필드 중 하나를 숫자로 구문 분석할 수 없는 경우 오류가 발생하도록 하고 싶습니다.
입력 예는 다음과 같습니다.
bob 1
dave 2
alice 3.5
foo bar
"bar"는 숫자가 아니기 때문에 오류를 무시하는 것이 아니라 오류가 발생하기를 원합니다.
답변1
이를 테스트하는 합리적인 방법은 다음과 유사한 테스트를 사용하여 필드를 비교하는 것입니다.strtod
, 어느 것이awk를 사용하는 방법문자열을 숫자로 변환:
$2 !~ / *[+-]?[[:digit:]]/ { print "NAN: " $2; exit 1; }
위와 strtod의 차이점은 INFINITY 또는 NAN을 "숫자"로 간주하지 않는다는 것입니다. awk의 기본 필드 분할 동작에 따라 선행 공백 요구 사항이 완화될 수 있습니다. 즉, 필드에는 선행 공백이 포함되지 않습니다.
$2 !~ /[+-]?[[:digit:]]/ { print "NAN: " $2; exit 1; }
Stéphane의 의견과여기에 대답하세요:
$2 !~ /^[+-]?([[:digit:]]*\.?[[:digit:]]*([eE][-+]?[[:digit:]]+)?|0[xX][[:xdigit:]]*\.?[[:xdigit:]]*([pP][-+]?[[:digit:]]+)?)$/ { print "NAN: " $2; exit 1; }
약간 더 나은 가독성을 위해 정규식은 다음과 같습니다.
/^[+-]?([[:digit:]]*\.?[[:digit:]]*([eE][-+]?[[:digit:]]+)?|\
0[xX][[:xdigit:]]*\.?[[:xdigit:]]*([pP][-+]?[[:digit:]]+)?)$/
...목적은 가능한 앞에 + 또는 -를 허용하고 그 뒤에 부동 소수점 또는 16진수 숫자가 오는 것을 허용하는 것입니다. 부동 소수점 숫자에는 선택적 선행 숫자, 옵션 구분 기호(여기서는 마침표로 고정됨 .
), 그 뒤에 자릿수, 선택적으로 지수가 옵니다. 16진수는 0x
또는 로 시작 해야 하며 0X
그 뒤에 16진수, 구분 기호, 추가 16진수 숫자가 오고 선택적으로 "제곱"(지수)이 와야 합니다. 두 번째 필드 전체는 다음 형식 중 하나와 일치해야 합니다( ^
및에 의해 고정됨 $
). 이 질문의 목적을 위해 NAN 및 INFINITY 옵션은 여기서 생략되었습니다.
또 다른 옵션은 숫자 변환을 강제로 수행한 다음 이를 0과 비교한 다음, 선택적 + 또는 -로 시작하는 경우 원래 입력을 0으로 변환할 입력과 추가로 비교한 다음 0 또는 가 뒤따르는 것입니다. 마침표와 0:
{ number=0 + $2;
if (!number && $2 !~ /^[+-]?(0+)|\.0+/)
print "NAN: "$2;
}
답변2
나는 이것으로 끝났습니다 :
awk -v col=$col '
typeof($col) != "strnum" {
print "Error on line " NR ": " $col " is not numeric"
noprint=1
exit 1
}
{
sum+=$col
}
END {
if(!noprint)
print sum
}' $file
이는 GNU awk 확장인 typeof를 사용합니다. typeof($col)
유효한 숫자이면 "strnum"을 반환하고 $col
, 그렇지 않으면 "할당되지 않음"을 반환합니다.
답변3
awk -v col=2 '
$col+0==0 && $col!~/^[+-]?0/ { print "bad number " $col > "/dev/stderr" }
{sum+=$col}
END{print sum}' input-file
.0
를 처리하거나 유효한 표현으로 사용하려는 경우 .0e+33
이를 복잡하게 만들 수 있습니다 . 문자열을 숫자로 변환할 때 후행 쓰레기( 또는 모두 14 와 같음) 0
는 무시됩니다.awk
"1.4e1e3"+0
"1.4e1.e7"+0
"14+13"+0
답변4
제가 사용하는 작은 비결은 문자열에서 제곱근을 구하는 것입니다. awk
올바른 결과를 얻기 위해 최선의 노력을 다할 것이므로 후행 0이 숫자가 아닌 경우 이 방법은 적합하지 않습니다.
if ( sqrt(_varname) ) {
print "this " _varname " is a (positive) number"
} else {
print "this " _varname " is not a number..."
}