Linuxでawkスクリプト内でソートするにはどうすればよいですか?

次の内容のファイルfruitがあります:

Apples, 12 Pears, 50 Cheries, 7 Strawberries, 36 Oranges, 2 

ファイルの数値データを並べ替えたい:

for(i=1;i<=NF;i++)j+=$i;printf "Fruit %d%s, %d\n",NR,OFS,$1,j | sort -k 2 > "numbers"; j=0" 

awkスクリプトを実行するには、次のコマンドを実行します:

awk -f numbers fruit 

数値ファイルの内容はフルーツと同じですが、1番目と2番目のフィールドが数値ファイルにコピーされます。

コメント

  • なぜawkでソートする必要があるのですか? Awkには'ネイティブの並べ替え機能がありませんが、'代わりに出力を並べ替えないのはなぜですか?
  • @ terdon GNU awk(Linuxのデフォルトのawkだと思います)にはネイティブの並べ替え機能があります。
  • @EdMortonは最後の質問を参照してください。いくつかのコンテキスト。そして、あなたは'正解です! GNUawkにはasortがあります。なんらかの理由で、' tしないと誓ったかもしれません。ありがとう! 'ファイル全体を配列に読み込んでから配列を並べ替える必要があるため、それが価値があるかどうかはよくわかりません。そのため、出力の並べ替えの方が効率的である可能性があります。ただし、'はこれで十分です。
  • @terdon 'は

また、はるかに便利なsorted_inがあり、for (i in array)の順序を簡単に定義できます。配列要素にアクセスします- gnu.org/software/gawk/manual/gawk.html#Controlling-Scanning.I を参照してください。UNIXソートにパイプするだけで、ただし、この問題にはより効率的です。

  • @EdMorton GNU awkは、debianなどのデフォルトではありません。 " mawk "がデフォルトであり、'には" sort "組み込み関数。
  • 回答

    GNU awkを使用すると、配列をトラバースする方法を制御できます。配列トラバーサルの制御およびスキャンの制御

    gawk -F", " " {fruit[$1] = $2} END { OFS = FS printf "\nordered by fruit name\n" PROCINFO["sorted_in"] = "@ind_str_asc" for (f in fruit) print f, fruit[f] printf "\nordered by number\n" PROCINFO["sorted_in"] = "@val_num_desc" for (f in fruit) print f, fruit[f] } " fruit 

    出力

    ordered by fruit name Apples, 12 Cheries, 7 Oranges, 2 Pears, 50 Strawberries, 36 ordered by number Pears, 50 Strawberries, 36 Apples, 12 Cheries, 7 Oranges, 2 

    回答

    実際にはawkのprint"sort"(引用符に注意してください):

    $ awk "{print "Fruit",NR, $0 | "sort -k 2 -t, -rn"}" fruit Fruit 2 Pears, 50 Fruit 4 Strawberries, 36 Fruit 1 Apples, 12 Fruit 3 Cheries, 7 Fruit 5 Oranges, 2 

    したがって、numbersに書き込むには、次のことができます。

    awk "{print "Fruit",NR, $0 | "sort -k 2 -t, -rn > numbers"}" fruit 

    awkを少し簡略化したことに注意してください。ここでprintfを使用したり、明示的に印刷したりする必要はありません。 OFSどこにも変更していないので。そのため、for(i=1;i<=NF;i++)j+=$iが何をしているのかわからないでください。すでにNRの番号があり、printfjを使用していませんでした。

    コメント

    • awk内でsortを呼び出す代わりに'簡単に印刷する方が簡単で効率的ですawkで、awk出力をパイプして並べ替えます:awk '{print ...}' fruit | sort ...
    • @EdMortonああ、絶対に!私はこのアプローチを自分で使用することは決してありません、what 'がポイントですか?しかし、これはOPが求めたものです
    • 並べ替える必要があることがよくありますgawk内で、'出力全体を並べ替えたくない場合。たとえば、入力ファイルごとに統計情報を個別に収集してレポートします。decorate/ sort / clipメソッドを使用して複雑なデータから単純なキーを調整します(たとえば、最大定格のサイドアレイを使用して電気機器の過負荷をランク付けします)。また、外部ソートではディスクワークファイルと分割/マージ戦略を使用します。内部sortはより良い方法を使用できます。
    • @JoeSkora ' awkからサブシェルを生成する必要はなく、関係するすべてのバッファリングが出力につながることを期待しますサブシェルから、awkコマンドからの残りの出力の前ではなく、その前、または該当する場合はその途中でstdoutに到達します。 awk '{print (NR>1), $0}' | sort -k1,1n -k2 | cut -d' ' -f2-
    • @EdMortonを実行するだけです。条件付きの素晴らしいアイデアを印刷するのが好きです。最後の部分は、これを残してさらに簡略化できます。 awk '{print (NR>1),$0}' | sort ... | cut -c3-

    回答

    深刻だったに違いありません2002年のSunOSnawkの問題。GNU以外のawk内で実行される3つのawk実装を含むテストスクリプトを見つけました。

    (a)eSort:ワークファイルを使用し、sortコマンドを実行するパイプを介して読み取ります。私の場合は良くありません。エージェントレス監視のためにsshを介して作業を行っていたため、外部の作業ファイルはライブサーバーには侵襲的すぎました。

    (b)qSort:再帰的なパーティションソート。大きなデータの場合はパフォーマンスが悪く、2000を超える要素の場合はmawkのスタックが壊れます。でも書くのは楽しい。

    (c)hSort:15行のin-situアルゴリズム。このヒープは、インデックスアルゴリズムを使用して、バイナリツリーをサポートします(Wikipediaを参照)。

    このbashスクリプトには、実際の並べ替えを実装するawk関数hSortおよびhUpが含まれています。 1つのアクション行がすべての入力を配列に入れ、ENDブロックがhSortを呼び出して結果を報告します。

    入力データは「manbash」の内容であり、1回は行として、もう1回は単語として使用されます。 wcを使用して何も失われていないことを証明し、sort-cを使用して出力がソートされていることを証明します。タイミングには、読み取りと印刷のオーバーヘッドが含まれます。

    これはテストショットです:

    Paul--) ./hSort Sorted 5251 elements. real 0m0.120s user 0m0.116s sys 0m0.004s 5251 44463 273728 hSort.raw sort: hSort.raw:2: disorder: 5251 44463 273728 hSort.srt Sorted 44463 elements. real 0m1.336s user 0m1.316s sys 0m0.008s 44463 44463 265333 hSort.raw sort: hSort.raw:3: disorder: Commands 44463 44463 265333 hSort.srt 

    これはスクリプトです。お楽しみください!

    #! /bin/bash export LC_ALL="C" #### Heapsort algorithm. function hSort { #:: (void) < text local AWK=""" #.. Construct the heap, then unfold it. function hSort (A, Local, n, j, e) { for (j in A) ++n; for (j = int (n / 2); j > 0; --j) hUp( j, A[j], n, A); for (j = n; j > 1; --j) { e = A[j]; A[j] = A[1]; hUp( 1, e, j - 1, A); } return (0 + n); } #.. Given an empty slot and its contents, pull any bigger elements up the tree. function hUp (j, e, n, V, Local, k) { while ((k = j + j) <= n) { if (k + 1 <= n && STX V[k] < STX V[k + 1]) ++k; if (STX e >= STX V[k]) break; V[j] = V[k]; j = k; } V[j] = e; } { U[++nU] = $0; } END { sz = hSort( U); printf ("\nSorted %s elements.\n", sz) | "cat 1>&2"; for (k = 1; k in U; ++k) print U[k]; } """ mawk -f <( printf "%s\n" "${AWK}" ) } #### Test Package Starts Here. function Test { time hSort < hSort.raw > hSort.srt for fn in hSort.{raw,srt}; do wc "${fn}"; LC_ALL="C" sort -c "${fn}"; done } AWK_LINE="{ sub (/^[ \011]+/, ""); print; }" AWK_WORD="{ for (f = 1; f <= NF; ++f) print $(f); }" #xxx : > hSort.raw; Test #.. Edge cases. #xxx echo "Hello" > hSort.raw; Test #xxx { echo "World"; echo "Hello"; } > hSort.raw; Test man bash | col -b | mawk "${AWK_LINE}" > hSort.raw; Test man bash | col -b | mawk "${AWK_WORD}" > hSort.raw; Test 

    回答

    HeapSortは標準のawkで簡単に記述できます20行以上。目がくらむほど速くはありませんが、言語に適度に適合しています。

    コメント

    • ああ、私は'投稿しないでください。私はその存在を主張し、読者のための演習として残しました。
    • 2020年1月9日にコードとテストを投稿しました

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です