grep语法与正则表达式不同吗?
我想从这里提取已删除软件包的名称“cat /var/log/dpkg.log | grep’remove’”
2013-09-09 15:57:34 remove activity-log-manager:i386 0.9.4-0ubuntu6.2 2013-09-09 15:57:35 remove activity-log-manager-control-center:i386 0.9.4-0ubuntu6.2 2013-09-09 15:57:38 remove alacarte:all 3.6.1-0ubuntu3 2013-09-09 15:57:41 remove deepin-software-center:all 2.1.2.1~precise~NoobsLab.com
我想只获取包名后删除和冒号之间的包的名称。 我不是一个正则表达式专家,我做了一个正则表达式似乎做了这个工作但是当我想用grep应用它时没有任何反应。 这是正则表达式评估器中正在运行的正则表达式模式
(?<=remove)(.*?)(?=:)
但这不起作用:
cat /var/log/dpkg.log | grep 'remove' | grep '(?<=remove)(.*?)(?=:)'
我在这里想念的是什么?
正则表达式语法有一个共同的核心,但有不同的风格。 您的表达式似乎包含一些特定于perl风格的特性,特别是使用描述要匹配的模式的开始和结束的复杂外观断言 ,而grep默认为仅支持更简单的基本正则表达式(BRE)语法这些零长度匹配的集合,如line-( ^
, $
)和word-anchors( \>
, \<
)。
您可以使用-P命令行开关在grep中启用perl兼容的正则表达式(PCRE)支持(但请注意,手册页当前将其描述为“experimental”)。 在您的情况下,您可能希望-o开关也只打印匹配的模式,而不是整行即ie
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 " | 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.
但是,您应该注意“可用function没有区别”并不意味着语法相同。 例如,在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]\+'
类似的区别适用于没有和使用-r
开关调用的sed
。
从grep
手册页:
对于包含与给定PATTERN匹配的行,grep搜索命名输入FILE(或标准输入,如果没有文件被命名,或者如果单个连字符 – ( – )作为文件名)。
据我所知, 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
的内容替换,第一组将被替换定义。