Вопрос или проблема
Формат файлов CSV выглядит следующим образом
"Пицца,крылья,мороженое","хоппер","0",,"Масдфасдф","США","381","10 УТ","кап",,,"монстр"
Использование запятой в качестве разделителя, как показано ниже, приведет к тому, что поля с запятыми будут считаться разделителями, чего я не хочу.
cat /path/to/file | cut -d , -f2
вернет
крылья
когда я хочу
хоппер
Я думаю, что логически нашел решение, но не уверен, как его реализовать.
Как мне сделать разделитель, который бы говорил: “Если я запятая, окруженная либо другой запятой, либо кавычками, считайте меня разделителем”?
Пример
[tksmith@rifle ~]$ cat deleteme
"Пицца,крылья,мороженое","хоппер","0",,"Масдфасдф","США","381","10 УТ","кап",,,"монстр"
[tksmith@rifle ~]$ cat deleteme | cut -d , -f2
крылья
Формат CSV имеет достаточно сложных случаев, чтобы вы не хотели заново изобретать его разбор. Используйте правильный парсер CSV. Например, с помощью Ruby
ruby -rcsv -e 'CSV.foreach(ARGV.shift) {|row| puts row[1]}' файл
Команда cut разделяет только один символ за раз. Так что вы можете преобразовать кавычки и запятые в другой разделитель с помощью sed и регулярного выражения. Например:
sed -e 's/","\|",\|,"\|,,/@/g' /path/to/file | cut -d@ -f2
Вернет
хоппер
Другой способ – использовать AWK. Например, следующее даст вам 2-е поле.
awk -F ',,|^"|","|",|,"|"$' '{print $3}' /path/to/file
вернет
хоппер
Приведенные выше примеры не идеальны, так как они не обрабатывают корректно все случаи с несколькими пустыми полями и внешними кавычками. Лучше использовать язык сценариев более высокого уровня с модулем для разбора CSV.
Вы должны использовать библиотеку для обработки CSV (как упоминали другие), например в Ruby:
ruby -rcsv -e 'CSV.foreach(ARGV.shift) {|row| puts row[1]}' файл
Но мой предпочтительный метод – использовать csvkit, установите его с помощью pip install csvkit
(если у вас уже есть рабочая среда Python).
А затем после добавления заголовков к файлу запустите его с помощью
csvcut -f second_column deleteme
Ответ или решение
Чтобы извлечь поля из CSV-файла, содержащих запятые, необходимо учитывать наличие кавычек (") вокруг некоторых значений. Использование стандартной команды cut
с разделителем в виде запятой не подходит, так как она не учитывает контекст, в котором могут находиться запятые – то есть, внутри кавычек. Рассмотрим несколько методов решения этой задачи.
1. Использование sed
для замены разделителей
Один из подходов заключается в предварительной обработке файла с использованием утилиты sed
, чтобы преобразовать проблемные запятые в другой разделитель. Например:
sed -e 's/","\|",\|,"\|,,/@/g' /path/to/file | cut -d@ -f2
Данный код работает следующим образом:
sed
заменяет запятые, которые находятся между кавычками или рядом с пустыми полями, на символ@
. Это позволяет изолировать нужные данные, чтобы затем использоватьcut
.- После этого
cut
может корректно извлечь второе поле на основе нового разделителя.
2. Использование awk
Другой, более мощный вариант заключается в использовании awk
, который позволяет задавать более сложные шаблоны для определения разделителей. Например:
awk -F ',,|^"|","|",|,"|"$' '{print $3}' /path/to/file
Здесь:
-F
задаёт несколько разделителей, включая запятые, которые могут находиться в разнообразных контекстах.$3
указывает на вывод третьего поля, что соответствует вашему примеру, если учитывать запятые и кавычки.
3. Использование языков программирования с поддержкой CSV
Как наиболее оптимальное решение, рекомендуется использовать подходящие языки программирования с готовыми библиотеками для обработки CSV. В Python, например, можно воспользоваться csvkit
, который упрощает работу с CSV-файлами:
-
Установите
csvkit
:pip install csvkit
-
После этого можно использовать команду
csvcut
для выбора нужного столбца, предварительно добавив заголовки в ваш CSV-файл:csvcut -f 2 deleteme
Также можно использовать язык Ruby с встроенной библиотекой CSV
:
ruby -rcsv -e 'CSV.foreach(ARGV.shift) {|row| puts row[1]}' deleteme
Заключение
Использование простых Unix-утилит для обработки CSV может оказаться неэффективным, особенно если в файле есть много нюансов, таких как запятые внутри кавычек или пустые поля. Поэтому, для более комплексных задач обработки CSV, лучше всего применять специализированные библиотеки и языки, которые обеспечивают более точное разбиение данных без необходимости самостоятельно разбираться с нюансами формата.