단일 열 번호 파일이 주어지면 호출될 때 f
다음 Awk 코드는 최대값을 반환합니다.
cat f | awk ' BEGIN {max = -inf}
{if ($1>max) max=$1}
END { print max }
'
최소값을 구하는 동일한 방법으로 결과가 나오지 않습니다.
cat f | awk '
BEGIN {min = inf}
{if ($1<min) min=$1}
END {print min}
'
그러나 을 inf
사용하지 않고 에서 시작하는 min = [some large number]
경우 숫자가 충분히 크면(파일 내용에 따라) 수정된 코드가 작동합니다.
왜 작동하지 않으며 파일에 무엇이 있는지 알지 않고도 사례를 사례처럼 처리할 inf
수 있는 방법이 있습니까 ?min
max
답변1
이것실제일가장 좋은 해결 방법은 가상의 "최소" 또는 "최대" 숫자(이 경우 사용 중인 프레임워크에서 달성하지 못할 수 있음 awk
)가 아닌 다음을 사용하여 최대/최소 값을 초기화하는 것입니다.실제데이터. 이렇게 하면 항상 의미 있는 결과가 보장됩니다.
귀하의 경우 규칙을 추가하여 처음 발견된 값(즉, 첫 번째 행의 항목)을 초기화 max
하고 각각 사용할 수 있습니다.min
NR==1{min=$1}
당신의 스크립트에 awk
. 그런 다음 첫 번째 값이 이미 최소값인 경우 후속 테스트에서는 이를 다루지 않고 결국 올바른 결과를 생성합니다. 최대값 검색에도 동일하게 적용되므로 결합 검색에서는 다음을 선언할 수 있습니다.
NR==1{max=min=$1}
inf
귀하의 방법이 작동하지 않는 이유는 무엇입니까?그리고 @steeldriver가 귀하의 질문에 대한 의견에 좋은 설명을 제공한 awk
것 같습니다 -inf
. 완전성을 위해 요약하겠습니다.
- 에서
awk
변수는 "동적으로 유형이 지정"됩니다. 즉, 사용법에 따라 모든 것이 문자열 또는 숫자가 될 수 있습니다(그러나awk
마지막으로 사용된 내용을 "기억"하고 다음 작업을 위해 해당 정보를 유지합니다). - 코드에서 변수와 관련된 산술 연산이 발견될 때마다
awk
해당 변수의 내용을 숫자로 해석하여 연산을 수행하려고 시도하며, 성공하면 거기에서 변수가 숫자로 입력됩니다. - 아무것도 할당되지 않은 변수의 기본값은 빈 문자열이며 산술 연산에서 0으로 해석됩니다.
- 이것변수 이름(*)
inf
특별한 의미가 없으므로awk
이렇게 사용하면 와 같은 산술식에서 0으로 평가되는 빈 변수이다-inf
. 따라서 데이터가 모두 양수인 경우max
변수가 0으로 초기화된 "최대 검색"이 작동합니다(따라서 음수가 아닌 가장 작은 숫자).-inf
-inf
- 그러나 "최소 검색" 문제에서는 이 빈 문자열을 숫자로 자동 변환하는 것을 보장하는 산술 연산이 없기 때문에 초기화는 변수를 빈 문자열로
min
초기화합니다 .inf
그래서 다음 비교에서는
if ($1<min) min=$1
입력은
$1
문자열 값과 비교되므로 문자열awk
로 처리되어 실행됩니다.$1
사전 편찬숫자보다는 비교해보세요.그러나 사전 편찬의 관점에서 보면,아무것도 없다빈 문자열보다 "작다".
min
안 돼요새로운 값이 할당됩니다. 따라서 이END
부분에서는 다음과 같이 명시한다.print min
(여전히) 빈 문자열을 인쇄합니다.
(*) 바라보다스티븐 키트의 답변어떻게내용이 포함된 문자열"inf"
실제로 이해가 될 수 있습니다 awk
.
답변2
inf
GNU AWK의 기본 비 POSIX 모드에서는 특별한 의미가 없기 때문에 귀하의 접근 방식이 작동하지 않습니다 . 결과적으로는 변수명으로 해석되며 변수에 아무 것도 설정되지 않았으므로 그 값은 산술 문맥에서는 0, 문자열 문맥에서는 빈 문자열이다. 따라서 코드는 양수의 최대값( max
산술 컨텍스트에서 초기화되기 때문에)만 찾고 최소값( min
문자열 컨텍스트에서 초기화되기 때문에)은 찾지 않습니다.관리자 꿀벌의 답변더 알아보기.
파일(또는 스트림)의 최소 및/또는 최대 값을 결정하려면 다음에 제공된 조언을 따라야 합니다.관리자 꿀벌의 답변.
그러나 GNU AWK를 사용하는 경우 log(0)
양수 또는 음수 무한대에서 변수 초기화를 계산하고 이를 메서드와 비슷한 방식으로 사용할 수 있습니다.
BEGIN { max = log(0) }
$1 > max { max = $1 }
END { print max }
BEGIN { min = -log(0) }
$1 < min { min = $1 }
END { print min}
첫 번째 행의 값을 초기화하는 것과 비교할 때 이 접근 방식의 유일한 장점은 처리되는 값이 없을 때 고유한 결과를 제공할 수 있다는 것입니다. 양수 또는 음수 무한대는 결과적으로 값이 표시되지 않았음을 나타내는 신뢰할 수 있는 지표가 됩니다. (첫 번째 줄에서 초기화할 때 0 대신 빈 문자열을 확인하는 것을 포함하여 이를 확인하는 다른 방법이 있습니다.)
예를 들어 , POSIX 모드( POSIXLY_CORRECT=1
)에서 GNU AWK를 사용하거나 다른 POSIX 호환 AWK 인터프리터를 사용하세요.mawk
"inf"
끈덕분에 산술 문맥에서 무한대가 생성됩니다.strtod
:
BEGIN { max = "-inf" + 0 }
$1 > max { max = $1 }
END { print max }
BEGIN { min = "+inf" + 0 }
$1 < min { min = $1 }
END { print min}
답변3
실제로 무한대에는 -inf
+inf
and inf
, 및 의 세 가지 값이 있습니다. 간단한 문제에 더 많은 복잡성을 추가하기 위해 awk에는 인용된 코드 상수와 인용되지 않은 코드 상수가 있습니다.
무슨 뜻인지 설명하려면 다음을 시도해 보십시오(awk 4.2.1(현재 Debian 10)의 쉘 코드).
for cmd in original-awk "busybox awk" mawk nawk awk; do
printf '%-6.5s' "$cmd"
$cmd 'BEGIN {
a="-inf";b="+inf";c="inf";
d= -inf ;e= +inf; f= inf;
printf "-∞%4s%4s +∞%4s%4s ∞%4s%4s | -∞%4s%4s +∞%4s%4s ∞%4s%4s\n",a,a+0,b,b+0,c,c+0,d,d+0,e,e+0,f,f+0}
' file
얻으려면 :
bawk -∞-inf-inf +∞+inf inf ∞ inf inf | -∞ 0 0 +∞ 0 ∞ 0
busyb -∞-inf-inf +∞+inf inf ∞ inf inf | -∞ 0 0 +∞ 0 0 ∞ 0
mawk -∞-inf-inf +∞+inf inf ∞ inf inf | -∞ 0 0 +∞ 0 0 ∞ 0
nawk -∞-inf-inf +∞+inf inf ∞ inf 0 | -∞ 0 0 +∞ 0 0 ∞ 0
gawk -∞-inf-inf +∞+inf inf ∞ inf 0 | -∞ 0 0 +∞ 0 0 ∞ 0
이 표는 인용된 변수 할당과 인용되지 않은 변수 할당(abcdef)을 보여줍니다.
각 경우에 대해 awk는 값을 읽고 숫자(var+0)로 변환합니다.
"-inf"
이는 a가 숫자인 경우에도 그대로 유지되고 a는 숫자 (부호 없이) "+inf"
로 변환되며 참조된 a는 구현에 따라 또는 이 될 수 있음을 의미합니다(nawk 및 gawk에서는 0 ) .inf
"inf"
inf
0
따옴표가 없으면 -inf
둘 다 +inf
됩니다 ( 빈 문자열 ""로 해석되어 로 변환되는 0
bawk 제외 ).+∞
0
이상한 점은 따옴표가 없으면 모든 것이 inf
빈 문자열로 해석된다는 것입니다.
그러나 모두 따옴표 없이 -inf
사용하면 +inf
0 이 됩니다.inf
var+0
따라서 원하는 작업에는 따옴표가 필요하며 "-inf"
절대 "+inf"
다음이 필요하지 않습니다 inf
.
cat file | awk ' BEGIN { max = "-inf"+0; min = "+inf"+0 }
{ if ($1>max) max=$1
if ($1<min) min=$1
}
END { print min, max }
'
아마도 이를 이해하는 더 간단한(이식 불가능한 방법)은 다음과 같습니다.
gawk 'BEGIN{
a="-inf";b="+inf";c="inf";
d= -inf ;e= +inf; f= inf;
print a, typeof(a), b, typeof(b), c, typeof(c)
print a+0, typeof(a+0), b+0, typeof(b+0), c+0, typeof(c+0)
print d,typeof(d),e,typeof(e),f,typeof(f)
print d+0,typeof(d+0),e+0,typeof(e+0),f+0,typeof(f+0)
}'
다음을 인쇄합니다:
-inf string +inf string inf string
-inf number inf number 0 number
0 number 0 number unassigned
0 number 0 number 0 number
물론 정확하고 이식 가능한 해결책은 max
처음부터 및 변수에 값을 할당하는 것입니다.min
cat file | awk ' NR==1 { min = max = $1 }
{ if ($1>max) max=$1
if ($1<min) min=$1
}
END { print min, max }
'
---
설명하다awk 매뉴얼에서예:
--posix
명령줄 옵션을 사용하면gawk
"그대로 놔둘" 수 있습니다. 문자열 값은 시스템 라이브러리의 strtod() 함수에 직접 전달되며, 성공적으로 숫자 값을 반환하면 해당 값이 사용됩니다. 정의에 따르면 결과는 다른 시스템에 이식될 수 없습니다. 그들은 또한 약간 놀랍습니다.$ echo influence | gawk --posix '{ print $1 + 0 }' -| inf $ echo 0xDeadBeef | gawk --posix '{ print $1 + 0 }' -| 3735928559
- 그렇지 않은 경우
--posix
'gawk
+inf', '-inf', '+nan' 및 '-nan' 4개의 문자열 값이 특별히 해석되어 해당 특수 값을 생성합니다. 선행 기호는 사용자(및 사용자)에게 값이 실제로 숫자라는 신호 역할을 합니다. 16진수 부동 소수점은 지원되지 않습니다(권장되지 않는 --non-decimal-data도 사용하지 않는 한). 예를 들어:$ echo nanny | gawk '{ print $1 + 0 }' -| 0 $ echo +nan | gawk '{ print $1 + 0 }' -| +nan $ echo 0xDeadBeef | gawk '{ print $1 + 0 }' -| 0
gawk
네 가지 특수 값의 경우는 무시합니다. 따라서 "+nan"과 "+NaN"은 동일합니다.입력을 처리하는 것 외에도
gawk
값이 NaN 또는 무한대인 경우 출력에 "올바른" 값을 인쇄해야 합니다. 버전 4.2.2부터 이러한 값의 경우gawk
방금 설명한 네 가지 문자열("+inf", "-inf", "+nan" 또는 "-nan") 중 하나가 인쇄됩니다. 마찬가지로 POSIX 모드에서는gawk
시스템 C 함수의 결과가 값의 형식 문자열(무엇이든)을 사용하여 인쇄됩니다.printf()
%g