1つの列が最大値などのテキストファイルから行を抽出します。

1つの列が最大値などのテキストファイルから行を抽出します。

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

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

これはかなり一般的な問題であり、ファイルに2回パスすることに関連する慣用的なawkソリューションがあります。最初のパスでは最大値が決定され$5、2番目のパスではその最大値を含むレコードが抽出されます$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に一度に1行ずつ処理し、各行をで指定されたコマンドに渡すように指示します-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}'

関連情報