У мене дивна проблема з великими файлами і bash
. Це контекст:
- У мене великий файл: 75G і 400 000 000+ рядків (це файл журналу, моє погано, я даю йому рости).
- Перші 10 символів кожного рядка - це часові позначки у форматі РРРР-ММ-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
дає результат нижче (я кладу x
es, щоб зберегти дані конфіденційними, інші символи - справжні). Зауважте, 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. Змінені версії bash
4.1.5 на Debian Squeeze 6.0.2 та 6.0.4.
echo ${BASH_VERSINFO[@]}
4 1 5 1 release x86_64-pc-linux-gnu
Оновлення3:
Завдяки Андреасу Швабу, який швидко відреагував на мій звіт про помилку, саме цей патч - це рішення цієї поведінки. Файл, який зазнав впливу, lib/sh/zread.c
як раніше вказував Жилл:
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
повертає зсув з початку файлу, коли він перевищує 2 Гб, int
значення негативне, що призводить до того, що тест if (r >= 0)
не виходить там, де він повинен був досягти успіху.
read
заяви у bash.