Подтвердить что ты не робот

Как заставить awk игнорировать полевой разделитель внутри двойных кавычек?

Мне нужно удалить 2 столбца в файле разделенных запятыми. Рассмотрим следующую строку в файле csv:

"[email protected],www.example.com",field2,field3,field4
"[email protected]",field2,field3,field4

Теперь результат я хочу в конце:

"[email protected],www.example.com",field4
"[email protected]",field4

Я использовал следующую команду:

awk 'BEGIN{FS=OFS=","}{print $1,$4}'

Но встроенная запятая, которая находится внутри кавычек, создает проблему. Ниже приводится результат, который я получаю:

"[email protected],field3
"[email protected]",field4

Теперь мой вопрос: как сделать awk игнорировать ",", которые находятся внутри двойных кавычек?

4b9b3361

Ответ 1

Из руководства GNU awk (http://www.gnu.org/software/gawk/manual/gawk.html#Splitting-By-Content):

$ awk -vFPAT='([^,]*)|("[^"]+")' -vOFS=, '{print $1,$4}' file
"[email protected],www.example.com",field4
"[email protected]",field4

и см. Каков наиболее надежный способ эффективного анализа CSV с использованием awk? для более широкого анализа CSV файлов, которые включают в себя новые строки и т.д. в пределах полей.

Ответ 2

Это не решение bash/awk, но я рекомендую CSVKit, который может быть установлен pip install csvkit. Он предоставляет набор инструментов командной строки для работы с CSV, в том числе csvcut, который делает именно то, что вы просите:

csvcut --columns=1,4 <<EOF
"[email protected],www.example.com",field2,field3,field4
"[email protected]",field2,field3,field4
EOF

Вывод:

"[email protected],www.example.com",field4
[email protected],field4

Он удаляет ненужные кавычки, которые, я полагаю, не должны быть проблемой.

Прочитайте документы CSVKit здесь, в RTD. ThoughtBot имеет приятный маленький пост в блоге, представляющий этот инструмент, в котором я узнал о CSVKit.

Ответ 3

В вашем примере входного файла это первое поле и только первое поле, которое цитируется. Если это вообще верно, тогда рассмотрите следующее как метод для удаления второго и третьего столбцов:

$ awk -F, '{for (i=1;i<=NF;i++){printf "%s%s",(i>1)?",":"",$i; if ($i ~ /"$/)i=i+2};print""}' file
"[email protected],www.example.com",field4
"[email protected]",field4

Как упоминалось в комментариях, awk не изначально понимает цитируемые разделители. Это решение работает вокруг этого, ища первое поле, которое заканчивается цитатой. Затем он пропускает два следующих поля.

Подробности

  • for (i=1;i<=NF;i++)

    Это запустит for по каждому полю i.

  • printf "%s%s",(i>1)?",":"",$i

    Отправляет поле i. Если это не первое поле, этому поле предшествует запятая.

  • if ($i ~ /"$/)i=i+2

    Если текущее поле заканчивается двойной кавычкой, это увеличивает счетчик полей на 2. Это то, как мы пропускаем поля 2 и 3.

  • print""

    После завершения цикла for это печатает новую строку.

Ответ 4

Этот awk должен работать независимо от того, где указано поле, и работает также с экранированными кавычками.

awk '{while(match($0,/"[^"]+",|([^,]+(,|$))/,a)){
      $0=substr($0,RSTART+RLENGTH);b[++x]=a[0]}
      print b[1] b[4];x=0}' file

Ввод

"[email protected],www.example.com",field2,field3,field4  
"[email protected]",field2,field3,field4  
field1,"[email protected],www.example.com",field3,field4  

Выход

"[email protected],www.example.com",field4
"[email protected]",field4
field1,field4

Он работает даже на

field1,"field,2","but this field has ""escaped"\" quotes",field4

То, что могучая переменная FPAT завершается с ошибкой!


Объяснение

 while(match($0,/"[^"]+",|([^,]+(,|$))/,a))

Запускает цикл while, который продолжается до тех пор, пока совпадение имеет успех (т.е. есть поле).
Соответствие соответствует первому появлению регулярного выражения, которое случайно совпадает с полями и сохраняет его в массиве a

 $0=substr($0,RSTART+RLENGTH);b[++x]=a[0]

Устанавливает $0 для начала в конце совпадающего поля и добавляет соответствующее поле в соответствующее положение массива в b.

  print b[1] b[4];x=0}

Распечатывает нужные поля с b и устанавливает x обратно к нулю для следующей строки.


Дефекты

Ошибка, если в поле содержатся как экранированные кавычки, так и запятая


Изменить

Обновлено для поддержки пустых полей

awk '{while(match($0,/("[^"]+",|[^,]*,|([^,]+$))/,a)){
     $0=substr($0,RSTART+RLENGTH);b[++x]=a[0]}
     print b[1] b[4];x=0}' file