Я хотел бы извлечь из файла дату в формате DD.MM.YYYY
, дата всегда в первой поместите здесь пример записей
15.04.2016 13:13:30,228 INFO [wComService] [mukumukuko@system/3] Call created with id:VoiceConnector$mukumukuko@system$D1:1:0:CB:SESSION$D1:1:0:DB:mukumukuko@system$D1:1:0:HB:_TARGET^M
15.04.2016 13:14:10,886 INFO [wComService] Call 5303 from device +41999999999^M
15.04.2016 13:14:20,967 INFO [AddressTranslatorService][mukumukuko@system/3] </convertLocalToGNF>^M
15.04.2016 13:14:20,992 INFO [wComService] [mukumukuko@system/3] Call created with id: VoiceConnector$mukumukuko@system$D1:1:0:MB:SESSION$D1:1:0:NB:mukumukuko@system$D1:1:0:RB:_TARGET^M
15.04.2016 13:15:18,760 INFO [OSMCService] SessionManager Thread - Heartbeat (1clients connected)^M
этот файл содержит журнал активности за 1 неделю, поэтому в файле можно найти даты, например 16.04.2016
, 17.04.2016
, 18.04.2016
а также.
Файл может также иметь следующие выходные данные из исключения Java:
at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanEndElement(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
Я пробовал следующее:
cat fac.log | sed 's/^.*\([0-9]\{2\}.[0-9]\{2\}.[0-9]\{4\}\).*$/\1/' > datesF1
но я получил желаемую дату в "dateF1", но с этими сообщениями об исключениях Java.
Я бы хотел чтобы сгенерировать файл, который отображает только уникальные даты без их повторения, например, «dateF1» должно быть:
15.04.2016
16.04.2016
17.04.2016
18.04.2016
Знаете ли вы, возможно ли это, или лучше использовать команду grep?
Причина, по которой ваша команда sed не работает, заключается в том, что она предполагает, что у вас есть дата в каждой строке, что не так, если некоторые строки поступают из многострочных сообщений об ошибках. Когда нет ничего, соответствующего шаблону замены, sed не выполняет замену, и списки стека вызовов, которые вы видели, остаются в выводе.
Чтобы получить даты только из строк, у которых они есть в начале, у вас есть несколько вариантов:
grep:
grep -Eo '^[0-9.]+' fac.log
-o указывает grep печатать только соответствующую часть, а не всю строку, а -E включает "расширенные" регулярные выражения
awk:
awk '/^[0-9.]+/ {print $1}' fac.log
Первая часть команды awk - это совпадение регулярного выражения, остальное - что делать с совпадающей строкой, здесь мы печатаем первое слово в строке.
Perl:
perl -lne 'print $1 if /^([0-9]+)/' fac.log
-l: выводить новую строку на каждом print
, -n: запускать команду для каждой строки ввода (например, awk), -e: просто сообщает, что программа дана на в командной строке, а не в файле.
Во всех случаях вы получаете одну строку вывода на соответствующую строку ввода, то есть повторяющиеся даты. Передача результата через | сортировать | uniq
, вероятно, самая простая идиома для удаления дубликатов.
Обратите внимание, что я был ленив и использовал ^ [0-9.] +
вместо более длинного и точного шаблона. Это связано с причиной, по которой мне нравится использовать perl вместо sed, awk и друзей: регулярные выражения Perl всегда одинаковы, независимо от того, что вы делаете.Также в Perl нет необходимости помнить, какие модификаторы поддерживаются по умолчанию, а какие требуют установки -E или чего-то еще. Кроме того, есть различия между версиями: по-видимому, в моих системах Debian по умолчанию используется mawk вместо GNU awk, и, похоже, он не поддерживает модификатор {N}, поэтому более точный шаблон не работал. Ой.
Руководство по GNU awk: «Интервальные выражения традиционно не были доступны в awk. Они были добавлены как часть стандарта POSIX, чтобы сделать awk и egrep согласованными друг с другом». (ref. https://www.gnu.org/software/gawk/manual/html_node/Regexp-Operators.html#Regexp-Operators )
awk '/^[0-9]{2}[.][0-9]{2}[.][0-9]{4}/ {DATES[$1]++}
END{ for(d in DATES) {print d} }'
В отличие от "камень, бумага, ножницы": awk всегда побеждает sed. :-)
Редактирование: вот он в действии:
$ cut -b-60 t
15.04.2016 13:13:30,228 INFO [wComService] [mukumukuko@sy
15.05.2016 13:14:10,886 INFO [wComService] Call 5303 from
15.06.2016 13:14:20,967 INFO [AddressTranslatorService][m
15.07.2016 13:14:20,992 INFO [wComService] [mukumukuko@sy
15.04.2016 13:15:18,760 INFO [OSMCService] SessionManager
this file contains the activity log of 1 week, so in the fil
The file can have also these outputs from Java exception:
at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanE
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl
at org.apache.xerces.parsers.XML11Configuration.parse(Un
at org.apache.xerces.parsers.XML11Configuration.parse(Un
$ awk '/^[0-9]{2}[.][0-9]{2}[.][0-9]{4}/ {DATES[$1]++}
END{ for(d in DATES) { print d } }' t
15.07.2016
15.06.2016
15.04.2016
15.05.2016
Это GNU awk. Если ваша версия awk не выводит результат, это, вероятно, потому, что ее реализация регулярных выражений отличается и не сопоставляет строки. Например, она может не поддерживать скобки как спецификатор повторения. Ценой потери специфичности можно упростить regex до /^[0-9]/
, что определенно сработает. Это позволит отловить даты и устранить сообщения журнала, но может зацепить и не даты.
Некоторые эксперименты и время, проведенное с вашим дружественным руководством по awk, могут оказаться плодотворными. ;-)
.