awk를 사용하여 마지막 줄을 먼저 처리하십시오.


11

awk마지막 데이터 포인트를 기반으로를 사용하여 정규화하려는 데이터 파일이 있습니다. 따라서 마지막 데이터 포인트에 먼저 액세스하여 데이터를 정규화 한 다음 정상적으로 처리하고 싶습니다.

tac두 번 사용하는 다음 방법 은 작업을 수행하지만 필요한 것보다 더 복잡 할 수 있습니다.

$ cat file
0 5
1 2
2 3
3 4
$ tac file | awk 'NR==1{norm=$2} {print $1, $2/norm}' | tac
0 1.25
1 0.5
2 0.75
3 1

내 질문은 다음과 같습니다 : awk 만 사용하여 위의 결과를 얻을 수 있습니까?

대답은 "아니요, awk는 파일을 한 줄씩 스캔합니다"라고 생각하지만 대안에 대한 제안은 열려 있습니다.

답변:


5

awk에서 2 패스 솔루션으로 할 수 있습니다.

awk 'FNR == NR { n = $2; next } { print $1, $2/n }' infile infile

awk 버전이 ENDFILE 블록 (예 : GNU awk 4+)을 지원하는 경우 다음과 같이 수행 할 수 있습니다.

awk 'ENDFILE { n = $2 } FNR != NR { print $1, $2/n }' infile infile

seek파일이 끝날 때까지 더 효율적 입니다. 먼저 camh 's answer를 참조하십시오 .

설명

첫 번째 예는 이전을 기억하여 작동합니다 $2. 즉, 로컬 라인 카운터 ( FNR)가 글로벌 라인 카운터 ( NR)와 같은 경우에만 평가됩니다 . 이 next명령은 다음 줄로 건너 뜁니다.이 경우 두 번째 인수를 구문 분석 할 때 마지막 블록 만 평가됩니다.

두 번째 예는 유사한 논리를 갖지만 입력 파일 끝에 도달하면 평가되는 ENDFILE 블록을 활용합니다.


첫 번째 예제는 제대로 작동하고 두 번째 예제는 제대로 작동하지 않습니다 $ awk --version GNU Awk 3.1.8. 두 개의 입력 파일을 처리하는 방법과 처리하는 방법에 대해 아주 작은 설명을 추가 할 수 있습니까 next?
Bernhard

1
@Bernhard : 편집 참조
Thor

6

데이터 소스가 여러 번 읽을 수있는 파일 인 경우 (즉, 스트림이 아닌 경우) 먼저 tail(1)마지막 행에서 원하는 데이터를 가져 와서 파일의 순차적 처리를 위해 awk에 전달해야합니다. tail파일의 끝까지 모든 데이터를 읽을 필요없이 마지막 줄을 읽습니다.

awk -v norm=$(tail -n 1 file | cut -d' ' -f2) '{print $1, $2/norm}' file

이것은 전체 파일이 버퍼 캐시에 맞지 않는 큰 파일에서 큰 승리가 될 것입니다 (즉, 각 패스마다 한 번씩 디스크에서 두 번 읽혀야 함을 의미 함). 마지막 줄에 도착하는 입력 작은 파일은 2 단계 접근 방식과 크게 차이가 없을 수 있습니다.


3

그것들을 배열에로드하고 그것을 뒤로 읽을 수 있습니다 :

awk '{x[i++]=$0} END{for (j=i-1; j>=0;) print x[j--] }'

더 효율적으로 할 수 있지만, 이런 종류의 awk도구가 왜 이것이 적합한 도구가 아닌지 를 보여줍니다 . 사용 tac가능한 경우 계속 사용 하면 GNU tac은 일반적으로이 작업을위한 다양한 도구 중에서 가장 빠릅니다.


- for루프를 사용하는 awk것이 해결책이 아니라는 데 동의합니다 .
Bernhard
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.