
У меня есть 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/;/./
- если мы дошли до этой точки (третье поле былонетпусто), замените точку с запятой на точку.