file.txt라는 텍스트 파일(헤더 줄 포함)이 있습니다. 특정 열의 최대값과 동일한 행을 추출하려고 합니다(최대값이 무엇인지 모르겠습니다).
ID t1 q1 t2 q2 q3
1 f 45 ex 1 45
2 r 47 tr 1 33
3 r 33 ex 2 44
4 f 44 s 0 55
5 e 32 ex 0 54
6 f 34 tr 2 46
$5 열의 최대값을 찾은 다음 열 5가 해당 숫자와 같은 행만 인쇄해야 합니다.
3 r 33 ex 2 44
6 f 34 tr 2 46
다음 코드는 작동한다고 생각하지만 파일이 크고 시간이 오래 걸리므로 더 빠른 솔루션을 찾고 있습니다(정렬을 사용하는 것일 수도 있음).
이것이 내가 지금 가지고 있는 것입니다:
먼저 최대값을 찾으세요.
max=`awk '{print $5}' file.txt | sort -nr | sed -n 2p`
그런 다음 열 5가 이 값과 같은 행을 선택합니다.
awk 'NR>1' file.txt|while read LINE; do value=`echo $LINE|awk '{print $5}'`; if [ $value -eq $max ]; then echo $LINE >> test.txt; fi; done
답변1
한 가지 방법은 파일을 한 번 읽고 max
관련 줄을 다시 인쇄하는 것입니다.
max=$(awk 'NR>1 && $5>max {max=$5}; END{print max}' file.txt) &&
awk -v max="$max" '$5==max' file.txt
또는 더 간결하게 말하면:
awk -v m="$(awk '(NR>1 && $5>m){m=$5};END{print m}' file.txt)" '$5==m' file.txt
여기서의 비결은 -v
변수를 에 전달할 수 있는 awk 플래그 입니다 awk
. 이 경우에는 먼저 최대값을 계산한 다음 awk
이를 변수로 지정했습니다 max
.
답변2
이는 상당히 일반적인 문제이며, 파일에 두 번 패스하는 것과 관련된 관용적인 awk 솔루션이 있습니다. 첫 번째 패스에서는 최대값이 결정되고 $5
, 두 번째 패스에서는 해당 최대값이 포함된 레코드가 추출됩니다 $5
. 이것은 간단한 예입니다.
awk 'NR == FNR && NR > 1{max = max < $5? $5: max; next}; $5 == max{print}' file.txt file.txt
답변3
메모리 사용량이 실제 문제가 아닌 경우 Perl의 일회용 버전은 다음과 같습니다.
perl -ane 'END { $"=""; print "@res"; } if($F[4] =~ /^\d+/ and $F[4] > $max) {
$max = $F[4]; @res = (); } push @res, $_ if($F[4] =~ /^\d+$/ and $max == $F[4]);' infile
-n
infile
Perl에게 한 번에 한 줄씩 처리하고 각 줄을 에 지정된 명령에 전달하도록 지시합니다 -e
. -a
Perl에게 필드 구분 기호(기본적으로 공백) 주위의 각 줄을 확장하고 이를 이름이 지정된 배열에 할당하도록 지시합니다 @F
. 결과적으로 우리는 각 행을 처리하고 이를 사용하여 $F[n]
행의 n번째 요소를 참조할 수 있습니다.
펄 자체:
END { $"=""; print "@res"; } # at the end of execution set the field separator to
# empty and print the contents of @res, which includes
# newlines when the matching rows were stored
if($F[4] =~ /^\d+/ and $F[4] > $max) { # if the 5th element of the line is solely a
$max = $F[4]; @res = (); # number and it's greater than $max (which
} # starts as undefined), set $max to this number
# and empty the @res results array.
push @res, $_ # push this line to @res ...
if($F[4] =~ /^\d+$/ and $max == $F[4]); # IF the 5th element is solely a
# number and equal to $max
논리는 $max
정의되지 않은 것에서 시작하는 것이며 @res
배열은 비어 있습니다. 5열에서 처음으로 숫자를 찾으면 이를 $max
빈 에 저장합니다 @res
. @res
또한 후속 행의 열 5에서 새로운 최대값을 찾으면 지우는 부작용도 있습니다. 별도의 확인으로 열 5가 동일하면 $max
이 행을 추가합니다 @res
(현재 최대값이 있는 행을 저장함). 모든 행에 대해 이 작업을 반복한 다음 블록을 실행하면 일반적으로 에 설정된 선행 공백 필드 구분 기호 없이 END { }
결과 배열의 내용이 인쇄됩니다 .@res
$"
이것은 에서도 가능할 수도 있지만 awk
내 것은 awk-fu
그다지 좋지 않았습니다!
답변4
파일의 값을 내림차순으로 정렬하고 값이 변경될 때까지 위에서부터 줄을 인쇄합니다.
sort -k 5n | awk 'NR==1 {max=$5} $5!=max {quit} {print}'