【发布时间】:2010-11-01 18:21:09
【问题描述】:
我有一个包含许多错误行的日志文件,例如:
Failed to add email@test.com to database
我可以通过一次 grep 调用过滤这些行:
grep -E 'Failed to add (.*) to database'
这很好用,但我真正想做的是让 grep(或我将输出传递到的另一个 Unix 命令)只输出匹配行的电子邮件地址部分。
这可能吗?
【问题讨论】:
我有一个包含许多错误行的日志文件,例如:
Failed to add email@test.com to database
我可以通过一次 grep 调用过滤这些行:
grep -E 'Failed to add (.*) to database'
这很好用,但我真正想做的是让 grep(或我将输出传递到的另一个 Unix 命令)只输出匹配行的电子邮件地址部分。
这可能吗?
【问题讨论】:
sed 不用 grep 也没问题:
sed -n 's/Failed to add \(.*\) to database/\1/p' filename
【讨论】:
你也可以只管 grep 到它自己 :)
grep -E 'Failed to add (.*) to database' | grep -Eo "[^ ]+@[^ ]+"
或者,如果“感兴趣的行”是唯一带有电子邮件的行,则只需使用最后一个 grep 命令而不使用第一个。
【讨论】:
你可以使用 sed:
grep -E 'Failed to add (.*) to database'| sed 's/'Failed to add \(.*\) to database'/\1'
【讨论】:
-o 将返回字符串集“无法将 some@addre.ss 添加到数据库”,而 OP 只需要 some@addre.ss。
grep -o 有用但不是专门针对正则表达式匹配的组,我的问题是我需要grep 而不是sed 来匹配多行模式下的换行符。我没有找到支持s/.../.../m 的东西,而是使用了grep -z。将其与另一个 grep -oz 配对,并且我的模式合作允许我只选择我想要的部分内容,这些线类型彼此足够不同,我有我的解决方案!考虑到这一点,尤其是在不尝试匹配整行的情况下,这可能是一个补丁区域..
最新版本的 GNU grep 有一个 -o 选项,它完全符合您的要求。 (-o 代表--only-matching)。
【讨论】:
-o 将显示与正则表达式匹配的部分,其中包含找到匹配项的整行。但@Olly 只想要第一个子组(电子邮件地址,没有周围的文字)。
这应该可以完成工作:
grep -x -e '(?<=Failed to add ).+?(?= to database)'
它使用肯定的前瞻断言,然后是电子邮件地址的匹配,然后是后向的后瞻断言。这确保它匹配整行,但实际上只消耗(并因此返回)电子邮件地址部分。
-x 选项指定 grep 应该匹配行而不是整个文本。
【讨论】:
-P 标志以支持前瞻和后瞻。至少后视表达式应该有固定的长度 - 没有 .* 或其中的任何内容。
或蟒蛇:
cat file | python -c "import re, sys; print '\r\n'.join(re.findall('add (.*?) to', sys.stdin.read()))"
【讨论】:
sed 的-r 选项允许不带反斜杠的正则表达式
sed -n -r 's/Failed to add (.*) to database/\1/p' filename
【讨论】:
如果你想使用grep,使用egrep会更合适;
About egrep
Search a file for a pattern using full regular expressions.
grep 并不总是具有完整的正则表达式功能。
【讨论】: