カテゴリ別に上位10個のテキストブロックを識別し、降順で並べ替えて表示する方法

カテゴリ別に上位10個のテキストブロックを識別し、降順で並べ替えて表示する方法

当社のシステム内のオブジェクトに対して完了した取引履歴は次のとおりです。

   1 BYM1 TSTAB 09NOV 0035 CAB
Sometext 01
   2 BYM1 TSTAB 09NOV 0035 CAB
Can be done - question   
   3 BYM1 TSTAB 09NOV 0035 CAB
Sometext 02
Sometext 03
   6 BYM3 TSTAA 09NOV 0400 CAA
Some 04 text 04
   7 BYM3 TSTAA 10NOV 0455 CAC
Sometext 06
Sometext 06 line 2
   8 BYM3 TSTAA 10NOV 0455 CAC
Sometext 07
   9 BYM2 TSTAC 10NOV 0619 CAD
Some 08 text 0008 ABCD
Some 08 text 0008 BB00
Some 08 text 0008 CC00
Some 08 text 0008 DD00
Some 08 text 0008 EE00
  10 BYM2 TSTAC 10NOV 0627 CAD
Something BBBBBSSDGFSDSF
  11 BYM2 TSTAC 10NOV 0627 CAD
Something else
  12 BYM2 TSTAC 10NOV 0627 CAD
What text here
  13 BYM4 TSTAC 10NOV 0711 CAD
Tired figuring out
  19 BYM3 TSTAA 11NOV 0438 CAE
Some 04 text 05 05 05
  20 BYM3 TSTAA 11NOV 0441 CAF
Not so confidential now
  21 BYM3 TSTAA 11NOV 0441 CAF
Some 00 text 0009 X1X2
  43 BYM3 TSTAA 11NOV 0441 CAD
Some 0A text 0009 ABCD
  44 BYM3 TSTAA 11NOV 0441 CAD
Some 1B text
  45 BYM3 TSTAA 12NOV 1455 CAC
Something 0AADDBB
8782 BYM3 TSTAA 12NOV 1610 CAD
Something 0AADDBB
8830 BYM3 TSTAA 12NOV 1612 CAA
Something 0AADDBB
9999 BYM3 TSTAA 12NOV 1722 CAA
Something 0AADDBB

テキストブロックは、最初の4文字の数字を含む行で始まります。 (この番号は実際には各取引が索引付けされるシリアル番号です。)ブロック(トランザクション)カテゴリは、数字を含む行の最後の3文字として定義されます。

「カテゴリ」に属するテキストブロックを検索し、結果のブロックをインデックス(番号)の降順でソートし、必要なブロック数を表示するawk、sed(、vi、grep)スクリプトを探しています。注文する。

たとえば、「CAD」カテゴリのブロック4つを検索したい場合、見たい結果は次のとおりです。

8782 BYM3 TSTAA 12NOV 1622 CAD
Something 0AADDBB
  44 BYM3 TSTAA 11NOV 0441 CAD
Some 1B text
  43 BYM3 TSTAA 11NOV 0441 CAD
Some 0A text 0009 ABCD
  13 BYM4 TSTAC 10NOV 0711 CAD
Tired figuring out

どうすればこれを達成できますか?どんな助けにも感謝します:-)

ベストアンサー1

これはgawk(GNU、つまりほとんどの「Linux」システムのバージョン)awkのソリューションです。検索したいカテゴリに設定し、表示したいレコード数に設定したとしますawk$cat$num

awk -vRS='\n[ 0-9][ 0-9][ 0-9][0-9] ' -vcat="$cat" -vnum="$num" \
    '   BEGIN { first=1; rec_ind=0}
        {       if (first) {
                        rec = $0
                        first=0
                } else {
                        rec = save_seq $0
                }
                findnl = index(rec, "\n")
                if (findnl < 7) exit
                thiscat = substr(rec, findnl-3, 3)
                if (cat == thiscat) records[++rec_ind] = rec
                if (length(RT) == 0) {
                        # print "This should be the last record."
                        save_seq = "Does not matter"
                } else if (length(RT) == 6) {
                        save_seq = substr(RT, 2, 5)
                } else {
                        print "Invalid RT: len =", length(RT)
                        exit
                }
        }
        END   { num_recs = asort(records, sorted_records, "@val_num_desc")
                if (num < num_recs) num_recs = num
                for (i=1; i<=num_recs; i++) {
                        print sorted_records[i]
                }
              }
    '

メモ:

  • -vRS='\n[ 0-9][ 0-9][ 0-9][0-9] 'awk の RS (レコード区切り記号) 変数を改行文字、最大 4 桁の整数シーケンス番号、スペースで構成される正規表現に設定します。データ行内に4桁(スペースが続く)があり、レコード区切り文字として解釈されないため、改行が含まれています。この正規表現は 007sumsを受け入れるので、少し混乱します12 4

    これを awk のレコード区切り文字に設定すると、各「トランザクション」に複数の行が含まれていても、単一の awk レコードとして扱われます。いくつかの欠点があります。

    • RS パターンの先頭に改行文字が含まれているため、先頭の   1 データはレコード区切り文字として認識されません。
    • これは記録だから仕切りスキーマに重要な情報が含まれていても、レコードの一部とは見なされません。

    我々はこれらの問題に対処します。

  • -vcat="$cat"同様-vnum="$num"に、awk変数 catnum値を対応するシェル変数に設定します。
  • BEGIN { first=1; rec_ind=0}first最初のレコードを識別し、特別に処理できるようにフラグを true(1) に初期化し、目的のrec_indカテゴリーに一致するレコードが累積されるように、レコード索引 ( ) を 0 に初期化します。
  • if (first)true(最初のレコードを処理中)で、recawk recordsと同じに設定されます$0。これには、4桁の数字で始まる次の行までのすべての行が含まれます(含まれていません)。また、最初の行の先頭には4桁の数字が含まれています。次にfirstフラグをfalse(0)に設定します。

    最初のレコードではない場合、4桁がありません(このレコードは仕切りrec)なので、保存されたシリアル番号()をにsave_seq関連付けてレコード()を設定します$0。 (save_seqこれについては後で議論します。)

  • findnl = index(rec, "\n")レコードで最初の改行文字を見つけます(レコードには複数行が含まれていることを覚えておいてください)。最初から7文字未満の場合、他の項目はもちろん、シリアル番号とカテゴリ(重複せず)を入れる場所がなく、エラーが発生します。それ以外の場合は、thiscat最初の改行文字の前の最後の3文字(つまり、トランザクションの最初の行の最後の3文字)からレコードのカテゴリ()を抽出します。その後、thiscat探しているカテゴリと一致すると、レコードが配列recordsに保存されます。
  • RTRSレコードの終端(現在のレコードの終わりのパターンと一致する文字)。残念ながら、現在のレコードの終わりは実際には次のレコードの始まりです。現在のレコードが最後のレコードの場合、これは空のRT文字列(長さ0)になります。それ以外の場合、長さは常に6文字(改行1文字、スペースまたは4桁、スペース1個)でなければなりません。最後の 5 文字を抽出し (たとえば改行文字を削除)、save_seq次のトランザクションのシーケンス番号なので として保存します。
  • データの終わりに達したら、レコードをソートします(値を数値として処理し、降順でソート)。次に、numそのうちの1つを印刷します。

おすすめ記事