Saya memiliki masalah aneh dengan file besar dan bash. Inilah konteksnya:
- Saya memiliki file besar: 75G dan 400.000.000 + baris (ini adalah file log, salah saya, saya biarkan tumbuh).
- 10 karakter pertama dari setiap baris adalah stempel waktu dalam format YYYY-MM-DD.
- Saya ingin membagi file itu: satu file per hari.
Saya mencoba dengan skrip berikut yang tidak berfungsi. Pertanyaan saya adalah tentang skrip ini tidak berfungsi, bukan solusi alternatif .
while read line; do
new_file=${line:0:10}_file.log
echo "$line" >> $new_file
done < file.log
Setelah debugging, saya menemukan masalah dalam new_filevariabel. Skrip ini:
while read line; do
new_file=${line:0:10}_file.log
echo $new_file
done < file.log | uniq -c
memberikan hasilnya di bawah (saya meletakkan xes untuk menjaga data rahasia, karakter lain adalah yang asli). Perhatikan dhstring dan lebih pendek:
...
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
...
Ini bukan masalah dalam format file saya . Script cut -c 1-10 file.log | uniq -chanya memberikan perangko waktu yang valid. Menariknya, bagian dari output di atas menjadi dengan cut ... | uniq -c:
3227382 2011-xx-x9
4474604 2011-xx-x0
5722027 2011-xx-x1
Kita dapat melihat bahwa setelah hitungan uniq 4474604, skrip awal saya gagal.
Apakah saya mencapai batas dalam bash yang saya tidak tahu, apakah saya menemukan bug di bash (sepertinya tidak mungkin), atau apakah saya melakukan sesuatu yang salah?
Perbarui :
Masalahnya terjadi setelah membaca 2G file. Jahitan readdan pengalihan tidak suka file yang lebih besar dari 2G. Namun masih mencari penjelasan yang lebih tepat.
Pembaruan2 :
Ini pasti terlihat seperti bug. Itu dapat direproduksi dengan:
yes "0123456789abcdefghijklmnopqrs" | head -n 100000000 > file
while read line; do file=${line:0:10}; echo $file; done < file | uniq -c
tetapi ini berfungsi dengan baik sebagai solusi (sepertinya saya menemukan penggunaan yang bermanfaat cat):
cat file | while read line; do file=${line:0:10}; echo $file; done | uniq -c
Bug telah diajukan ke GNU dan Debian. Versi yang terpengaruh adalah bash4.1.5 pada Debian Squeeze 6.0.2 dan 6.0.4.
echo ${BASH_VERSINFO[@]}
4 1 5 1 release x86_64-pc-linux-gnu
Pembaruan3:
Terima kasih kepada Andreas Schwab yang bereaksi cepat terhadap laporan bug saya, ini adalah tambalan yang merupakan solusi untuk perilaku buruk ini. File yang terpengaruh adalah lib/sh/zread.cseperti yang Gilles tunjukkan lebih cepat:
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;
The rvariabel digunakan untuk menyimpan nilai kembali dari lseek. Ketika lseekmengembalikan offset dari awal file, ketika lebih dari 2GB, intnilainya negatif, yang menyebabkan tes if (r >= 0)gagal di tempat yang seharusnya berhasil.
readpernyataan dalam bash.