ฉันมีปัญหาแปลก ๆ bashกับไฟล์ขนาดใหญ่และ นี่คือบริบท:
- ฉันมีไฟล์ขนาดใหญ่: 75G และ 400,000,000 บรรทัดขึ้นไป (เป็นไฟล์บันทึกที่ไม่ดีฉันปล่อยให้มันเติบโต)
- 10 ตัวอักษรแรกของแต่ละบรรทัดคือการประทับเวลาในรูปแบบ YYYY-MM-DD
- ฉันต้องการแยกไฟล์: หนึ่งไฟล์ต่อวัน
ฉันลองใช้สคริปต์ต่อไปนี้ซึ่งใช้งานไม่ได้ คำถามของฉันเป็นเรื่องเกี่ยวกับสคริปต์นี้ไม่ได้ทำงานไม่ได้แก้ปัญหาทางเลือก
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
ให้ผลการร้อง (ฉันใส่xes เพื่อเก็บข้อมูลเป็นความลับตัวอักษรอื่น ๆ เป็นของจริง) สังเกต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 4474604สคริปต์เริ่มต้นของฉันล้มเหลว
ฉันตีขีด จำกัด ด้วยการทุบตีที่ฉันไม่รู้หรือไม่ฉันพบข้อผิดพลาดในการทุบตี (มันไม่น่าจะเกิดตะเข็บ) หรือฉันทำสิ่งผิดปกติหรือไม่?
อัปเดต :
ปัญหาเกิดขึ้นหลังจากอ่านไฟล์ 2G มันตะเข็บreadและการเปลี่ยนเส้นทางไม่ชอบไฟล์ขนาดใหญ่กว่า 2G แต่ยังคงค้นหาคำอธิบายที่แม่นยำยิ่งขึ้น
อัปเดต 2 :
ดูเหมือนว่าจะเป็นข้อบกพร่อง สามารถทำซ้ำได้ด้วย:
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 เวอร์ชันที่ได้รับผลกระทบคือbash4.1.5 สำหรับ Debian Squeeze 6.0.2 และ 6.0.4
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)ที่จะล้มเหลวที่มันควรจะมีประสบความสำเร็จ
readคำสั่งในการทุบตี