Я хочу разделить большой файл (> 15G, несколько миллионов записей) на более мелкие фрагменты с определенным количеством записей.Я использую Ubuntu 16.04.
Вот правила:
- В случае проблем с переносимостью я хотел бы придерживаться команд UNIX.
- Существует определенный шаблон, определяющий конец каждой записи('$$$$') во входном файле.
- Этот шаблон должен быть сохранен для отдельных записей в чанах
- Каждый чанк должен содержать n записей
- Каждая запись можетразличаются по числу строк.
Я искал похожие вопросы как этот , но не смог найти именно то, что искал.
Вотпример синтаксиса входного файла.
example.sdf
Item1
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.7946 2.9241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-2.9708 2.9673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
3
$$$$
Element2
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.6161 1.7634 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-2.7956 1.8496 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
5
$$$$
Something3
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.0580 0.5134 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
-3.5772 1.1545 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
10
$$$$
Требуемый вывод для n = 2:
example.sdf.chunk000001
Item1
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.7946 2.9241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-2.9708 2.9673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
3
$$$$
Element2
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.6161 1.7634 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-2.7956 1.8496 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
5
$$$$
example.sdf.chunk000002
Something3
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.0580 0.5134 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
-3.5772 1.1545 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
10
$$$$
В данный момент я пытался добиться этого с помощью split и awk (см. Ниже), но это выглядит неуклюже.Я также попытался взглянуть на csplit, но не смог найти ни одной опции для установки определенного количества записей в каждом чанке.
split
Команда split работает отлично, но не принимает разделитель $$$$, так как он содержит более одного символа.Я могу заставить его работать, заменив этот шаблон одним символом (@), но все может пойти не так, если этот другой символ будет найден в файле SDF.
# replace the separator with a dummy
sed -e 's/\$\$\$\$/@/g' export.sdf > example.sdf.tmp
# split the file (3 records) into smaller chunks (xaa, xab, ect.) with max 2 records
split -t @ -l 2 example.sdf.tmp
# replace the dummy with the proper separator
for f in xa*; do tail -n +2 $f |sed 's/@/\$\$\$\$/g' > $f.fixed; done
К сожалению, это выглядит не оченьоптимизирован для редактирования входного файла, а затем для каждого чанка, поэтому я попытался использовать вместо этого awk.
awk
Я новичок в awk, но мне удалось получить это:
awk 'NR%2==1 {x=sprintf(".chunk%06d",++i);} END {printf "%s",$0} {print>FILENAME x}' RS="\\$\\$\\$\\$" ORS="\$\$\$\$" example.sdf
Первый блок выглядит именно так, как я ищу, но во втором есть две ошибки:
example.sdf.chunk000002
[ blank line ]
Something3
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.0580 0.5134 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
-3.5772 1.1545 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
10
$$$$
$$$$
Как видите, естьпустая строка (которую я не мог отобразить, поэтому вместо нее я набрал [пустую строку]) в начале файла и один последний конечный шаблон в конце последнего фрагмента.Я также попробовал файл с 9 записями, я получил пустую строку в начале фрагментов 2-5 и окончательный дополнительный '$$$$' в конце фрагмента 5).
Как я могисправить это поведение, чтобы я получил ожидаемый результат?
Любая помощь будет высоко ценится!
Жозе Мануэль