大きなファイルとbash。これはコンテキストです:
- 私は大きなファイルを持っています:75Gと400,000,000行(これはログファイルです、私の悪い、私はそれを成長させました)。
- 各行の最初の10文字は、YYYY-MM-DD形式のタイムスタンプです。
- そのファイルを分割したい:1日1ファイル。
動作しなかった次のスクリプトを試しました。 私の質問は、このスクリプトが機能しないことであり、代替ソリューションではありません。
while read line; do
new_file=${line:0:10}_file.log
echo "$line" >> $new_file
done < file.log
デバッグ後、new_file変数に問題が見つかりました。このスクリプト:
while read line; do
new_file=${line:0:10}_file.log
echo $new_file
done < file.log | uniq -c
結果を以下に示します(xデータを機密に保つためにes を入れましたが、他のcharsは実際のものです)。に注意してくださいdhと短い文字列に。
...
27402 2011-xx-x4
27262 2011-xx-x5
22514 2011-xx-x6
17908 2011-xx-x7
...
3227382 2011-xx-x9
4474604 2011-xx-x0
1557680 2011-xx-x1
1 2011-xx-x2
3 2011-xx-x1
...
12 2011-xx-x1
1 2011-xx-dh
1 2011-xx-x1
1 208--
1 2011-xx-x1
1 2011-xx-dh
1 2011-xx-x1
...
私のファイルの形式に問題はありません。スクリプトcut -c 1-10 file.log | uniq -cは有効なタイムスタンプのみを提供します。興味深いことに、上記の出力の一部は次のようになりcut ... | uniq -cます。
3227382 2011-xx-x9
4474604 2011-xx-x0
5722027 2011-xx-x1
uniq countの4474604後、最初のスクリプトが失敗したことがわかります。
私は知らないbashの制限に達しましたか、bashのバグを見つけましたか(継ぎ目はありません)、または何か間違ったことをしましたか?
更新:
この問題は、ファイルの2Gを読み取った後に発生します。継ぎ目readとリダイレクトは2Gよりも大きなファイルを好みません。しかし、より正確な説明を探しています。
Update2:
間違いなくバグのように見えます。以下で再現できます:
yes "0123456789abcdefghijklmnopqrs" | head -n 100000000 > file
while read line; do file=${line:0:10}; echo $file; done < file | uniq -c
しかし、これは回避策としてうまく機能します(私は有用な使用を見つけたと継ぎますcat)
cat file | while read line; do file=${line:0:10}; echo $file; done | uniq -c
バグがGNUとDebianに報告されました。影響を受けるバージョンはbash、Debian Squeeze 6.0.2および6.0.4上の4.1.5です。
echo ${BASH_VERSINFO[@]}
4 1 5 1 release x86_64-pc-linux-gnu
Update3:
私のバグレポートに迅速に反応してくれたAndreas Schwabのおかげで、これがこの不正行為の解決策であるパッチです。影響を受けるファイルはlib/sh/zread.c、Gillesがすぐに指摘したとおりです。
diff --git a/lib/sh/zread.c b/lib/sh/zread.c index 0fd1199..3731a41 100644
--- a/lib/sh/zread.c
+++ b/lib/sh/zread.c @@ -161,7 +161,7 @@ zsyncfd (fd)
int fd; { off_t off;
- int r;
+ off_t r;
off = lused - lind; r = 0;
r変数は、の戻り値を保持するために使用されますlseek。lseekそれが2GBを超える場合、ファイルの先頭からのオフセットを返し、int値はテストが原因と否定、であるif (r >= 0)、それは成功していなければならない場所を失敗します。
readbash のステートメントの制限の方向を指すように継ぎ目があります。