区切り文字を含むレコードを含む大容量テキストファイル(300 MB)があります\n\n
。各行は、数字(フィールドラベル/名前)で始まり、その後にタブ文字とフィールドの内容/値が続くフィールドです。
110 something from record 1, field 110
149 something else
111 any field could be repeatable
111 any number of times
120 another field
107 something from record 2, field 107
149 fields could be repeatable
149 a lot of times
149 I mean a LOT!
130 another field
107 something from record 3
149 something else
各レコードは100 KBを超えることはできません。
以下では、問題のある履歴(制限より大きい)を見つけることができます。このレコード/「段落」から行末を削除します。そして長さを調べる:
cat records.txt | awk ' /^$/ { print; } /./ { printf("%s ", $0); } ' | awk '{print length+1}' | sort -rn | grep -P "^\d{6,}$"
次のいずれかで、間違ったレコードを処理する方法を見つけようとします。
- 制限より大きいレコードを削除します。
- 既知の問題を持つ特定のタグ(上記の例では149)のすべてのエントリを削除します。 149フィールドで始まるすべての行を削除すると、制限を超えるレコードがないと想定できます。
おそらく、制限に合わせて特定のフィールド/タグを十分に削除するには、スクリプト全体が必要です。最後のエントリを最初に削除することをお勧めします。
これは古いライブラリファイル形式に関連しています。ISO 2709。
ベストアンサー1
問題のある記録だけをスキップしたい場合:
awk 'BEGIN { ORS=RS="\n\n" } length <= 100*1000' file
これにより、100,000文字以下のすべてのレコードが印刷されます。
レコードが大きすぎる場合、特定の正の整数で始まるフィールドを削除するには、次の手順を実行します。
awk -v number=149 'BEGIN { ORS=RS="\n\n"; OFS=FS="\n" }
length <= 100*1000 { print; next }
{
# This is a too long record.
# Re-create it without any fields whose first tab-delimited
# sub-field is the number in the variable number.
# Split the record into an array of fields, a.
nf = split($0,a)
# Empty the record.
$0 = ""
# Go through the fields and add back the ones that we
# want to the output record.
for (i = 1; i <= nf; ++i) {
split(a[i],b,"\t")
if (b[1] != number) $(NF+1) = a[i]
}
# Print the output record.
print
}' file
以前と同様に、短いレコードが印刷されます。長いレコードは削除され、最初のタブで区切られたサブフィールドが数字number
(ここではコマンドラインで149と指定されている)のすべてのフィールドが削除されます。
大規模なレコードの場合、不要なフィールドなしでレコードが再生成されます。内部ループはタブのフィールドを分割し、タブで区切られた最初のサブフィールドではなくフィールドを追加して出力レコードを再作成しますnumber
。
for (i = 1; i <= nf; ++i) {
split(a[i],b,"\t")
if (b[1] != number) $(NF+1) = a[i]
}
POSIX仕様は、awk
複数文字の値を指定しない場合に発生する状況を公開するため(ほとんどの実装ではこれを正規表現として扱う)、厳密に一貫した実装の代わりにRS
使用できます。これにより、データの複数の空行が空のレコードを分離しなくなります。RS=""; ORS="\n\n"
ORS=RS="\n\n"
awk