다음 awk 스크립트가 있습니다.
{
if ($1 > 1000) {
print $0
}
}
첫 번째이자 유일한 열의 값이 1000보다 큰 모든 행을 인쇄해야 합니다.
테스트 데이터는 다음과 같습니다.
1,151
1001,055
756,75788
을 사용하면 awk -f my_script.awk my_data
다음과 같은 결과가 나타납니다.
1001,055
756,75788
내가 기대하는 것:
1001,055
awk 버전은 다음과 같습니다.
GNU Awk 5.0.0, API: 2.0 (GNU MPFR 4.0.2, GNU MP 6.1.2)
내가 뭘 잘못했나요?
편집하다:
의견에서 말했듯이 :
여기서 쉼표는 구분 기호가 아니라 프랑스어에서 사용되는 소수 구분 기호이며 Wikipedia에 따르면 영어를 제외한 모든 표기 시스템에서 사용됩니다.
편집 2: 샘플 데이터에는 열이 하나만 있습니다. 실제 데이터에서 필드 구분 기호는 ";"입니다.
답변1
부인 성명아래의 첫 번째 해결 방법은 원래 문제에 대한 오해로 인해 더 이상 사용되지 않습니다. 일치하는 솔루션은 편집 1과 2를 참조하세요.
awk
쉼표는 기본적으로 구분 기호로 인식되지 않습니다. 탭과 공백에 대해서만 이 작업을 수행합니다. 따라서 구분 기호를 명시적으로 정의해야 하며, 그렇지 않으면 awk
문자열 값을 비교해야 합니다.
BEGIN {FS=","}
$1 > 1000
조건이 충족되면 한 줄을 인쇄하는 간단한 표기법도 사용하고 있습니다. 이는 더 간단한 코드에 대한 힌트일 뿐입니다.
또는 명령줄에서 구분 기호를 지정합니다.
awk -F, -f script.awk infile
편집 1다음 사양은 ,
소수 구분 기호로 사용됩니다. 소수 구분 기호 awk
로 처리되며 소수 구분 기호를 사용하는 로케일은 문제가 되는 경우가 많습니다..
옵션 1의 경우 약간의 트릭을 권장합니다. 정수와 분수를 쉼표로 구분된 별도의 필드로 유지하고 개별적으로 평가합니다.
BEGIN {FS=","}
$1==1000 && $2>0 || $1 > 1000
그러면 a) 로캘 사용 시도를 건너뛰고 b) awk
-와 -구분 사이를 앞뒤로 번역하는 시도를 건너뜁니다. 단점은 부동 소수점 데이터가 많은 경우 필드 번호가 열 헤더와 일치하지 않을 수 있다는 것입니다. 그러나 실제로 일치하는 줄만 인쇄하는 경우에는 작동하지 않습니다.,
.
이렇게 입력
1,151
1001,055
756,75788
1000
1000,00
1000,000001
돌아올 것이다
1001,055
1000,000001
편집 2또 다른, 아마도 더 우아한 옵션은 비교를 위해 첫 번째 필드를 점으로 구분된 부동 소수점으로 변환하는 것입니다.
gensub(/,/,".","g",$1)+0 > 1000
이는 다음과 같이 작동합니다. 필드 1을 문자열로 해석하고, 로 대체하고 ,
, .
추가하여 0
-logic에서 숫자로 만들고 awk
, 조건이 true이면 비교하고 인쇄합니다. 장점은 ;
필드 구분 기호로 사양을 통해 이 솔루션에서 필드 번호 지정 문제가 발생하지 않는다는 것입니다.
일반적으로 ,
가능하면 소수 구분 기호를 사용하지 않는 것이 좋습니다. 물론 이는 데이터를 제공하는 사람에 따라 다릅니다.
답변2
@Ed Morton 및 @steeldriver의 의견을 답변에 추가하려면 GNU awk에게 쉼표를 소수 구분 기호로 처리하고 활성화하거나 --posix
/ --use-lc-numeric
정의 된 로케일을 사용하도록 할 수 있습니다 -N
.
예를 들어:
$ LC_NUMERIC=fi_FI.UTF-8 awk -N '$1 > 1000' data.txt
1001,055
또는:
$ LC_NUMERIC=fi_FI.UTF-8 awk --posix '$1 > 1000' data.txt
1001,055
점을 소수 구분 기호로만 처리하는 한, 그런 것은 756,75788
숫자로 인식되지 않고 문자열로 인식되며 비교는 문자열 기반입니다. 7
이후 정렬 1
및 ,
이전 정렬 0
, 따라서 756,75788
> 1000
및 1,151
< 입니다 1000
. (로케일의 대조 규칙도 사용하는지 확실하지 않지만 ,
해석 방법에 영향을 미칠 수 있습니다.)
($1 + 0)
다음을 사용하여 값을 숫자로 처리하도록 강제할 수 있습니다. 이것은 질문의 데이터에 작동하는 것 같지만 예를 들어 1000,1
인쇄 1000
되지 않습니다. "1000보다 큼"이 아닌 "최소 1000"을 확인하려면 ($1 + 0) >= 1000
소수 부분을 사용하고 무시하면 됩니다.
바라보다:6.1.4.2 로케일 환경이 변환에 영향을 미칩니다그리고6.3.2.1 문자열 유형과 숫자 유형GNU awk 매뉴얼에 있습니다. (나중 페이지의 예는 37
< 42
비교가 텍스트인지 숫자인지는 중요하지 않기 때문에 어리석은 것입니다.)