Я хочу извлечь имя удаленных пакетов отсюда "cat /var/log/dpkg.log | grep 'remove'"
2013-09-09 15:57:34 remove activity-log-manager:i386 0.9.4-0ubuntu6.2 <none>
2013-09-09 15:57:35 remove activity-log-manager-control-center:i386 0.9.4-0ubuntu6.2 <none>
2013-09-09 15:57:38 remove alacarte:all 3.6.1-0ubuntu3 <none>
2013-09-09 15:57:41 remove deepin-software-center:all 2.1.2.1~precise~NoobsLab.com <none>
Я хочу получить только имя пакетов между remove и двоеточие после имени пакета. Я не эксперт по регулярным выражениям, я сделал регулярное выражение, которое, кажется, выполняет свою работу, но когда я хочу применить его с помощью grep, ничего не происходит. Вот рабочая модель регулярных выражений в оценщиках регулярных выражений
(?<=remove)(.*?)(?=:)
Но это не работает:
cat /var/log/dpkg.log | grep 'remove' | grep '(?<=remove)(.*?)(?=:)'
Чего мне здесь не хватает?
Со страницы руководства grep
:
grep ищет именованные входные ФАЙЛЫ (или стандартный ввод, если не указано ни одного файла, или если в качестве файла указан один дефис-минус (-) name) для строк, содержащих совпадение с заданным PATTERN.
blockquote>Насколько я знаю,
grep
не имеет возможности редактировать строки, которые ему соответствуют; Я бы использовалsed
или, возможно,tr
для этого. Любое из следующего должно получить то, что вы хотите:cat /var/log/dpkg.log | grep 'remove' | sed 's/.*remove \([^:]*\):.*/\1/' cat /var/log/dpkg.log | grep 'remove' | sed -E 's/.*remove ([^:]*):.*/\1/' cat /var/log/dpkg.log | sed -n '/remove/s/.*remove \([^:]*:\).*/\1/p' cat /var/log/dpkg.log | sed -nE '/remove/s/.*remove ([^:]*):.*/\1/p'
Я, честно говоря, не уверен, что ваши
(?<=remove)(.*?)(?=:)
пытаются достичь. В регулярных выражениях скобки используются для определения групп захвата: вы можете видеть, что я использовал их в командах sed здесь - там все сопоставленное будет заменено содержимым группы захвата/1
, первой группы быть определенным.
Существует общее ядро синтаксиса регулярных выражений, но есть разные разновидности. Кажется, что ваше выражение содержит некоторые особенности, специфичные для Perl, в частности, использование сложных обходных утверждений , описывающих начало и конец сопоставляемого шаблона, тогда как grep по умолчанию использует базовое регулярное выражение (BRE) синтаксис, который поддерживает только более простой набор этих совпадений нулевой длины , таких как line- (^
, $
) и якоря слов (\>
, \<
).
Вы можете включить поддержку perl-совместимого регулярного выражения (PCRE) в grep, используя ключ командной строки -P (хотя обратите внимание, что страница руководства в настоящее время описывает ее как «экспериментальную»). В вашем случае вы, вероятно, хотите, чтобы ключ -o также печатал только соответствующий шаблон, а не всю строку, т. Е.
cat /var/log/dpkg.log | grep 'remove' | grep -oP '(?<=remove)(.*?)(?=:)'
Имейте в виду, что это выражение может завершиться ошибкой, если оно встретит пакеты, у которых нет суффикса: i386, так как оно может читать вперед до соответствующего двоеточия в следующем слове, например
echo "2013-09-07 08:31:44 remove cifs-utils 2:5.1-1ubuntu2 <none>" | grep -oP '(?<=remove)(.*?)(?=:)'
cifs-utils 2
Возможно, вы захотите взглянуть на awk, например,
cat /var/log/dpkg.log | awk '$3 ~ /remove/ {sub(":.*", "", $4); print $4}'
Помимо BRE и PCRE, Gnu grep имеет дополнительный режим, называемый расширенным регулярным выражением (ERE), определяемым переключателем командной строки -E. Страница руководства отмечает, что
In GNU grep, there is no difference in available functionality
between basic and extended syntaxes.
Однако вы должны заметить, что «отсутствие различий в доступной функциональности» не означает, что не означает , что синтаксис тот же. Например, в BRE символ +
обычно обрабатывается как литерал и становится только модификатором, означающим «один или несколько экземпляров предыдущего регулярного выражения», если его экранировать, т. Е.
$ echo "123.456" | grep '[0-9]+\.[0-9]+'
$ echo "123.456" | grep '[0-9]\+\.[0-9]\+'
123.456
, тогда как для ERE это совершенно противоположное
$ echo "123.456" | grep -E '[0-9]+\.[0-9]+'
123.456
$ echo "123.456" | grep -E '[0-9]\+\.[0-9]\+'
Аналогичное различие применяется для sed
, вызванного без и с переключателем -r
.