Tôi có một vấn đề lạ với các tập tin lớn và bash
. Đây là bối cảnh:
- Tôi có một tệp lớn: 75G và hơn 400.000.000 dòng (đó là tệp nhật ký, xấu của tôi, tôi để nó phát triển).
- 10 ký tự đầu tiên của mỗi dòng là dấu thời gian ở định dạng YYYY-MM-DD.
- Tôi muốn chia tập tin đó: một tập tin mỗi ngày.
Tôi đã thử với đoạn script sau không hoạt động. Câu hỏi của tôi là về kịch bản này không hoạt động, không phải giải pháp thay thế .
while read line; do
new_file=${line:0:10}_file.log
echo "$line" >> $new_file
done < file.log
Sau khi gỡ lỗi, tôi tìm thấy vấn đề trong new_file
biến. Kịch bản này:
while read line; do
new_file=${line:0:10}_file.log
echo $new_file
done < file.log | uniq -c
đưa ra kết quả dưới đây (Tôi đặt x
es để giữ bí mật dữ liệu, các ký tự khác là dữ liệu thực). Lưu ý dh
và các chuỗi ngắn hơn:
...
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
...
Nó không phải là một vấn đề trong định dạng của tập tin của tôi . Kịch bản cut -c 1-10 file.log | uniq -c
chỉ cung cấp tem thời gian hợp lệ. Thật thú vị, một phần của đầu ra trên trở thành cut ... | uniq -c
:
3227382 2011-xx-x9
4474604 2011-xx-x0
5722027 2011-xx-x1
Chúng ta có thể thấy rằng sau khi đếm uniq 4474604
, kịch bản ban đầu của tôi đã thất bại.
Tôi đã đạt đến một giới hạn trong bash mà tôi không biết, tôi đã tìm thấy một lỗi trong bash (nó không có khả năng), hoặc tôi đã làm gì sai?
Cập nhật :
Vấn đề xảy ra sau khi đọc 2G của tập tin. Nó đường nối read
và chuyển hướng không thích các tệp lớn hơn 2G. Nhưng vẫn đang tìm kiếm một lời giải thích chính xác hơn.
Cập nhật2 :
Nó chắc chắn trông giống như một lỗi. Nó có thể được sao chép với:
yes "0123456789abcdefghijklmnopqrs" | head -n 100000000 > file
while read line; do file=${line:0:10}; echo $file; done < file | uniq -c
nhưng điều này hoạt động tốt như một cách giải quyết (nó là một cách sử dụng hữu ích cat
):
cat file | while read line; do file=${line:0:10}; echo $file; done | uniq -c
Một lỗi đã được gửi đến GNU và Debian. Các phiên bản bị ảnh hưởng là bash
4.1.5 trên Debian Squeeze 6.0.2 và 6.0.4.
echo ${BASH_VERSINFO[@]}
4 1 5 1 release x86_64-pc-linux-gnu
Cập nhật 3:
Nhờ Andreas Schwab, người đã phản ứng nhanh chóng với báo cáo lỗi của tôi, đây là bản vá là giải pháp cho hành vi sai trái này. Các tập tin bị ảnh hưởng là lib/sh/zread.c
như Gilles đã chỉ ra sớm hơn:
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;
Các r
biến được sử dụng để giữ giá trị trả lại lseek
. Vì lseek
trả về phần bù từ phần đầu của tệp, khi nó có dung lượng trên 2 GB, int
giá trị âm, điều này khiến cho bài kiểm tra if (r >= 0)
thất bại ở nơi đáng lẽ phải thành công.
read
câu lệnh trong bash.