한 열이 최대값과 같은 텍스트 파일에서 행을 추출합니다.

한 열이 최대값과 같은 텍스트 파일에서 행을 추출합니다.

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

-ninfilePerl에게 한 번에 한 줄씩 처리하고 각 줄을 에 지정된 명령에 전달하도록 지시합니다 -e. -aPerl에게 필드 구분 기호(기본적으로 공백) 주위의 각 줄을 확장하고 이를 이름이 지정된 배열에 할당하도록 지시합니다 @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}'

관련 정보