Этот ответ в настоящее время предполагается, что файл CSV прекрасно согласуется и просто (как в выборочных данных), так что:
- Поле всегда имеет двойные кавычки вокруг них.
- Нет таких полей, как
"…""…"
, чтобы указать двойную кавычку, встроенную в строку.
- Между кавычками (
"this,that"
) нет полей с запятыми.
Учитывая эти предпосылки, этот sed
скрипт делает работу:
sed 's/^\("[^"]*",\)\{4\}"\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}",/&"YYYY-MM-DD HH:MM:SS",/'
Давайте разделим этот шаблон поиска на куски:
^\("[^"]*",\)\{4\}
Match начало строки за которым следуют: 4 повторения двойной кавычки, последовательность из нуля или более не двойных кавычек, двойная цитата и запятая.
Другими словами, это идентифицирует первые четыре поля.
"\([0-9]\{1,3\}\.\)\{3\}
матча двойные кавычки, а затем 3 повторов 1-3 десятичных цифр, за которыми следует точка - первые три тройки с IPv4 десятичном адреса.
[0-9]\{1,3\}",
матч 1-3 десятичных цифры следует двойной кавычка и запятая - последний триплет из IPv4 десятичного адреса плюс конец поля.
Очевидно, что для каждой индивидуальности CSV-файлов, с которыми вам также необходимо иметь дело, вы должны изменить регулярные выражения. Это не тривиально.
Используя расширенные регулярные выражения (включены по -E
как на GNU и BSD sed
), вы могли бы написать:
sed -E 's/^("(([^"]*"")*[^"]*)",){4}"([0-9]{1,3}\.){3}[0-9]{1,3}",/&"YYYY-MM-DD HH:MM:SS",/'
Узор распознавать первые 4 поля является более сложным, чем раньше. Он соответствует 4 повторениям: двойная кавычка, ноль или более вхождений {нулевых или более не двойных кавычек, за которыми следуют две двойные кавычки}, за которыми следуют ноль или более не двойных кавычек, за которыми следуют двойная кавычка и запятая.
Вы также можете написать, что в классических sed
(основных регулярных выражений) с либеральной окроплением обратной косой черты:
sed 's/^\("\(\([^"]*""\)*[^"]*\)",\)\{4\}"\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}",/&"YYYY-MM-DD HH:MM:SS",/'
Учитывая данные файла:
"12345","","","None","192.168.2.1","qqq","000"
"67890","ABC-1234-5678","9.9","Low","192.168.2.1","qqq","000"
"23456","Quaternions","2.3","Pisces","Heredotus","qqq","000"
"34567","Commas, oh commas!","3.14159","""Quotes"" quoth he","192.168.99.37","zzz","011"
"45678","Commas, oh commas!","3.14159","""Quote me"",""or not""","192.168.99.37","zzz","011"
Первый сценарий показан производит вывод :
"12345","","","None","192.168.2.1","YYYY-MM-DD HH:MM:SS","qqq","000"
"67890","ABC-1234-5678","9.9","Low","192.168.2.1","YYYY-MM-DD HH:MM:SS","qqq","000"
"23456","Quaternions","2.3","Pisces","Heredotus","qqq","000"
"34567","Commas, oh commas!","3.14159","""Quotes"" quoth he","192.168.99.37","zzz","011"
"45678","Commas, oh commas!","3.14159","""Quote me"",""or not""","192.168.99.37","zzz","011"
Первые две строки правильные mapp ред; третий правильно не изменился, но последние два должны были отображаться и не были.
Вторые и третьи команды производят:
"12345","","","None","192.168.2.1","YYYY-MM-DD HH:MM:SS","qqq","000"
"67890","ABC-1234-5678","9.9","Low","192.168.2.1","YYYY-MM-DD HH:MM:SS","qqq","000"
"23456","Quaternions","2.3","Pisces","Heredotus","qqq","000"
"34567","Commas, oh commas!","3.14159","""Quotes"" quoth he","192.168.99.37","YYYY-MM-DD HH:MM:SS","zzz","011"
"45678","Commas, oh commas!","3.14159","""Quote me"",""or not""","192.168.99.37","YYYY-MM-DD HH:MM:SS","zzz","011"
Обратите внимание, что Heredotus не модифицированная (правильно), а последние две строк получить строку даты добавлена после IP-адреса (также правильно).
Эти последние регулярные выражения не для слабонервных.
Очевидно, что если вы хотите настаивать на том, что IP-адреса соответствуют только номерам в диапазоне 0..255 в каждом компоненте, без ведущего 0, вам нужно усилить часть соответствия IP-адресов регулярному выражению. Это можно сделать; это некрасиво. Это проще всего сделать это с расширенными регулярными выражениями:
([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])
Вы хотите использовать этот блок в месте каждого [0-9]{3}
единицы в регулярных выражениях, показанных ранее.
Обратите внимание, что это все еще не пытается обрабатывать поля, не окруженные двойными кавычками.
Он также не определяет значение для замены из команды date
. Это выполнимо с (если элементарно не то) рутиной сценариев оболочки тщательно управления цитатой:
dt=$(date +'%Y-%m-%d %H:%M:%S')
sed -E 's/^("(([^"]*"")*[^"]*)",){4}"([0-9]{1,3}\.){3}[0-9]{1,3}",/&"'"$dt"'",/'
'…"'"$dt"'",/'
последовательностью является частью того, что начинается как одинарные кавычками.Первая двойная кавычка - это простые данные в строке; следующая одинарная кавычка заканчивает цитирование, "$dt"
интерполирует значение из date
внутри двойных кавычек оболочки (так что пространство не вызывает никаких проблем), тогда одинарная кавычка возобновляет однокаскадную нотацию, добавляя еще одну двойную кавычку, запятую и слэш перед строкой (аргумент sed
) завершается.
Почему вы не можете использовать awk? Это было бы намного лучше. –
Что должно произойти на линиях, где $ 5 не является IP-адресом? –
Насколько чист ваш CSV-файл? Есть ли поля без двойных кавычек вокруг них? Существуют ли когда-либо поля с символом '... ...? ...? ', Чтобы указать двойную кавычку, встроенную в строку? Существуют ли поля с запятыми между кавычками ('' this, that '')? Это не ужасно критично, но нужно ли задавать значение «YYYY-MM-DD HH: MM: SS» из переменной (например, выход «date +»% Y-% m-% d% H:% M:% S'' захватывается и заменяется командой 'sed')? –