bash 管道到 grep 并使用正则表达式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15162904/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Piping to grep and using regex
提问by Skyline969
Basically what I want to do is parse lines in a file and return usernames. Usernames are always surrounded in < and >, so I want to use regex to match eveything before (and including) the < and everything after (and including) the >, and then invert my match. I understand that grep -vE should be able to do this.
基本上我想做的是解析文件中的行并返回用户名。用户名总是被 < 和 > 包围,所以我想使用正则表达式来匹配 < 之前(并包括)< 和之后(包括)> 的所有内容,然后反转我的匹配。我知道 grep -vE 应该能够做到这一点。
My script looks a little something like this so far:
到目前为止,我的脚本看起来有点像这样:
#!/bin/bash
while read line; do
echo $line | grep -vE '(.*<)|(>.*)'
done < test_log
And test_log consists of the following:
test_log 包含以下内容:
Mar 1 09:28:08 (IP redacted) dovecot: pop3-login: Login: user=<emcjannet>, method=PLAIN, rip=(IP redacted), lip=(IP redacted)
Mar 1 09:27:53 (IP redacted) dovecot: pop3-login: Login: user=<dprotzak>, method=PLAIN, rip=(IP redacted), lip=(IP redacted)
Mar 1 09:28:28 (IP redacted) dovecot: imap-login: Login: user=<gconnie>, method=PLAIN, rip=(IP redacted), lip=(IP redacted), TLS
Mar 1 09:27:25 (IP redacted) dovecot: imap-login: Login: user=<gconnie>, method=PLAIN, rip=(IP redacted), lip=(IP redacted), TLS
However, when running my script, nothing is returned, despite when I test the regex in something like regexpal with an inverse match it does exactly what I want. What am I doing wrong?
但是,在运行我的脚本时,没有返回任何内容,尽管当我在具有反向匹配的 regexpal 之类的东西中测试正则表达式时,它完全符合我的要求。我究竟做错了什么?
回答by Kent
try this grep line:
试试这个 grep 行:
grep -Po "(?<=<)[^>]*"
or more secure:
或更安全:
grep -Po "(?<=user=<)[^>]*"
EDIT
编辑
short explanation
简短说明
-P perl-regex
-o only matching
you can get above info from man page
(?<=foo)bar look-behind assertion. matches bar, only if bar is following foo.
[^>]* any not > characters.
回答by Victor Signaevskyi
Actually, I like @Kent's answer too and it is correct, but sometimes it is difficult to remember switches like "-Po"for "grep"utility. Usually if you don't remember exact flag you may ask grep utility to refresh your memory in a following way:
其实,我喜欢@肯特的答案也和它是正确的,但有时很难记住像开关“-Po”为“grep的”实用工具。通常,如果您不记得确切的标志,您可以要求 grep 实用程序以下列方式刷新您的记忆:
$ grep --help | grep regex
-E, --extended-regexp PATTERN is an extended regular expression (ERE)
-G, --basic-regexp PATTERN is a basic regular expression (BRE)
-P, --perl-regexp PATTERN is a Perl regular expression
-e, --regexp=PATTERN use PATTERN for matching
-w, --word-regexp force PATTERN to match only whole words
-x, --line-regexp force PATTERN to match only whole lines
As we can see, there also another possible options, like "-E".
正如我们所看到的,还有另一个可能的选项,比如"-E"。
回答by Kaleb Pederson
I actually like @Kent's answer better, but if we can assume a recent version of grep and you want to avoid perl based regular expressions you can still extract the username directly:
我实际上更喜欢@Kent 的回答,但是如果我们可以假设是最新版本的 grep 并且您想避免基于 perl 的正则表达式,您仍然可以直接提取用户名:
echo $line | grep -o '<[^>]*>' | grep -o '[^<>]*'
回答by William
You don't really need an external program if your data is as consistent as you show.
如果您的数据与您显示的一样一致,则您实际上并不需要外部程序。
while read line; do
line="${line#*user=<}" # Remove from left up to <
line="${line%%>*}" # Remove to right from >
echo $line
done < test_log

