
当社のシステム内のオブジェクトに対して完了した取引履歴は次のとおりです。
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桁(スペースが続く)があり、レコード区切り文字として解釈されないため、改行が含まれています。この正規表現は007
sumsを受け入れるので、少し混乱します12 4
。これを awk のレコード区切り文字に設定すると、各「トランザクション」に複数の行が含まれていても、単一の awk レコードとして扱われます。いくつかの欠点があります。
- RS パターンの先頭に改行文字が含まれているため、先頭の
1
データはレコード区切り文字として認識されません。 - これは記録だから仕切りスキーマに重要な情報が含まれていても、レコードの一部とは見なされません。
我々はこれらの問題に対処します。
- RS パターンの先頭に改行文字が含まれているため、先頭の
-vcat="$cat"
同様-vnum="$num"
に、awk変数cat
とnum
値を対応するシェル変数に設定します。BEGIN { first=1; rec_ind=0}
first
最初のレコードを識別し、特別に処理できるようにフラグを true(1) に初期化し、目的のrec_ind
カテゴリーに一致するレコードが累積されるように、レコード索引 ( ) を 0 に初期化します。if (first)
true(最初のレコードを処理中)で、rec
awk recordsと同じに設定されます$0
。これには、4桁の数字で始まる次の行までのすべての行が含まれます(含まれていません)。また、最初の行の先頭には4桁の数字が含まれています。次にfirst
フラグをfalse(0)に設定します。最初のレコードではない場合、4桁がありません(このレコードは仕切り
rec
)なので、保存されたシリアル番号()をにsave_seq
関連付けてレコード()を設定します$0
。 (save_seq
これについては後で議論します。)findnl = index(rec, "\n")
レコードで最初の改行文字を見つけます(レコードには複数行が含まれていることを覚えておいてください)。最初から7文字未満の場合、他の項目はもちろん、シリアル番号とカテゴリ(重複せず)を入れる場所がなく、エラーが発生します。それ以外の場合は、thiscat
最初の改行文字の前の最後の3文字(つまり、トランザクションの最初の行の最後の3文字)からレコードのカテゴリ()を抽出します。その後、thiscat
探しているカテゴリと一致すると、レコードが配列records
に保存されます。RT
RS
レコードの終端(現在のレコードの終わりのパターンと一致する文字)。残念ながら、現在のレコードの終わりは実際には次のレコードの始まりです。現在のレコードが最後のレコードの場合、これは空のRT
文字列(長さ0)になります。それ以外の場合、長さは常に6文字(改行1文字、スペースまたは4桁、スペース1個)でなければなりません。最後の 5 文字を抽出し (たとえば改行文字を削除)、save_seq
次のトランザクションのシーケンス番号なので として保存します。- データの終わりに達したら、レコードをソートします(値を数値として処理し、降順でソート)。次に、
num
そのうちの1つを印刷します。
答え2
Linuxの原則「1つのタスク - 1つのツール」に従ってください。
必要なブロックのみを印刷します(例を参照
CAD
)。sed '/^\s*[0-9].*CAD/!d;:a;N;/\n\s*[0-9]/! s/\n/\x0/;ta;P;D'
逆順に並べ替え
sort -rn
最初に要求されたチャンクのみを取得します(例を参照
4
)。head -4
ほとんどのLinuxコマンドは次のように実行されます。ワイヤー(いいえ彫刻\n
) したがって、ewラインをnull-symbol()に変更してそれをラインに変換して\x0
渡します。ティー。
したがって、すべての行は次のようになります。
sed '/^\s*[0-9].*CAD/!d;:a;N;/\n\s*[0-9]/! s/\n/\x0/;ta;P;D' test.txt |
sort -rn |
head -4 |
tr '\0' '\n'
いいねGマンの回答R
フローセパレータのアイデアを変えましたが、S
この状況にはうまくいきません。一般的な方法では簡単です。
awk '
/^[ 0-9]{4} /{ #for start block string
if($NF==cat){ #if it is a needed block
idx=$1
BLOCK[idx]=$0 #put line onto array with asigned index
}
else
idx=0 #otherways asign index to 0
next #end itteration, go to start with next line
}
idx{ #pass inappropriate blocks (with 0-index)
BLOCK[idx]=BLOCK[idx] "\n" $0 #add line to array element with index
}
END{ #when finish all lines
for(i=0;i<num;i++){ #do num times
max=0 #asing `max` variable to min value
for(idx in BLOCK){ #for each index in array
idx=idx+0 #convert string index into decimal
if(idx>max)
max=idx #find maximum index (field No.1 in block)
}
if(!max)
exit #exit script if array empty (no more blocks)
print BLOCK[max] #print block with maximum index
delete BLOCK[max] #remove array element for furure search
}
}' cat="CAD" num=4 test.txt
答え3
たとえば、数字で始まる6つのフィールドの行でブロックの開始を検出でき、データに文字コード\001
(control-a)が含まれていないと仮定すると、ブロック内のすべての行を1行に連結して任意のフィールドを置き換えることができます。コードの改行文字です。その後、行を並べ替えて最初の4行を取得し、コードを改行文字に置き換えます。
#!/bin/bash
num=${1?number} cat=${2?category}
awk -vcat="$cat" '
/^ *[0-9]+ / && NF==6 { ok = ($NF==cat)
if(ok && sep!="")sep = "\n"
}
ok { printf "%s%s",sep,$0; sep = "\001" }
END { if(sep!="")printf "\n" }' |
sort -nr -k1,1 | head -"$num" |
tr '\001' '\n'
$NF
フィールド(最後のフィールド)が必須カテゴリの場合、awkは行を連結します。このsep
変数は最初は空でブロック内に""
入り、新しいブロックが開始されるときに使用されます。一致するものがない場合、最後の改行文字が最後に追加されます。\001
\n
答え4
v =とnum =の値を変更してみてください。
$ awk '$NF==v{F=1;print;next}F&&NF!=6{print}F&&NF==6{F=0}' v="CAC" test.txt | awk '$NF~v{val=j++;F=1}F{Arr[val]=Arr[val]"\n"$0}END{n=asorti(Arr,S_Arr);for(i=n;i>=n-num;i--){print Arr[i]}}' v="CAC" num=4
45 BYM3 TSTAA 12NOV 1455 CAC
Something 0AADDBB
8 BYM3 TSTAA 10NOV 0455 CAC
Sometext 07
7 BYM3 TSTAA 10NOV 0455 CAC
Sometext 06
Sometext 06 line 2
$ awk '$NF==v{F=1;print;next}F&&NF!=6{print}F&&NF==6{F=0}' v="CAD" test.txt | awk '$NF~v{val=j++;F=1}F{Arr[val]=Arr[val]"\n"$0}END{n=asorti(Arr,S_Arr);for(i=n;i>=n-num;i--){print Arr[i]}}' v="CAD" num=4
8782 BYM3 TSTAA 12NOV 1610 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