![Регулярное выражение для объединения полей в CSV](https://rvso.com/image/1317163/%D0%A0%D0%B5%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D0%BE%D0%B5%20%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%B4%D0%BB%D1%8F%20%D0%BE%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F%20%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9%20%D0%B2%20CSV.png)
У меня есть CSV-файл с более чем 2 миллионами записей в следующем формате.
path;name;extension;size;date;user
/foo/;difacs;cgi;3,795;18-07-2011;Unix User\pads
/foo/;difacs.cgi;bak;2,622;03-12-2009;Unix User\pads
/foo/test/kzt/netcdfSample/testing/;zzz;;401;27-07-2006;Unix User\kzt
/foo/test/kzt/netcdfSample/vic_netcdf_popup/;a;txt;1,832;17-02-2006;Unix User\kzt
Мне нужно объединить путь, имя и расширение в одно правильно отформатированное поле.
path;size;date;user
/foo/difacs.cgi;3,795;18-07-2011;Unix User\pads
/foo/difacs.cgi;bak;2,622;03-12-2009;Unix User\pads
/foo/test/kzt/netcdfSample/testing/zzz/;401;27-07-2006;Unix User\kzt
/foo/test/kzt/netcdfSample/vic_netcdf_popup/a.txt;1,832;17-02-2006;Unix User\kzt
Заранее спасибо!
решение1
Это вариация ответа slhck, которая правильно обрабатывает пустое поле расширения (и избегает ложной замены точки, которая могла намеренно существовать во втором или третьем поле):
sed 's/^\([^;]*\);\([^;]*\)/\1\2/;ta;:a;s/^[^;]\+;;/&/;t;s/;/./' inputfile
Не обязательно использовать третью группу захвата. Этот ответ работает и без нее. Не обязательно экранировать точку справа от команды замены.
Вот объяснение моего сценария:
- захватите первые два поля, за исключением точек с запятой, которые их разделяют.
ta;:a
- если замена прошла успешно, то переходим к метке,:a
которая следует сразу за ней - это фактически снимает флаг "успешно"s/^[^;]\+;;/&/
- заменить последовательность не-точек с запятой, за которой следуют две точки с запятой (объединенные первое и второе поля, за которыми следует пустое третье поле) на себя — это пустая операция, но она устанавливает флаг «успешно».t
- если последняя замена прошла успешно (третье поле пустое), перейти к концу обработки текущей строки (так как метка не указана)s/;/./
- если мы дошли до этой точки (третье поле былонетпусто), замените точку с запятой на точку.