基本上我想要做的是解析文件中的行并返回用户名。用户名总是包围在<和>,所以我想使用正则表达式来匹配(包括)<之前的eveything。以及(包括)>之后的所有内容,然后反转我的匹配。我知道grep -vE应该能够做到这一点。
到目前为止,我的脚本看起来有点像这样:
#!/bin/bash
while read line; do
echo $line | grep -vE '(.*<)|(>.*)'
done < test_log
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
然而,在运行我的脚本时,没有返回任何内容,尽管当我使用反向匹配测试regex之类的正则表达式时它完全符合我的要求。我做错了什么?
答案 0 :(得分:18)
尝试这个grep行:
grep -Po "(?<=<)[^>]*"
或更安全:
grep -Po "(?<=user=<)[^>]*"
修改强>
简短说明
-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.
答案 1 :(得分:2)
实际上,我也喜欢@ Kent的答案,这是正确的,但有时很难记住像&#34; -Po&#34; 这样的& #34; grep&#34; 实用程序。通常,如果您不记得确切的标记,您可以通过以下方式请求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
正如我们所看到的,还有另一种可能的选择,例如&#34; -E&#34; 。
答案 2 :(得分:1)
我实际上更喜欢@ Kent的答案,但是如果我们可以假设最新版本的grep而你想避免使用基于perl的正则表达式,你仍然可以直接提取用户名:
echo $line | grep -o '<[^>]*>' | grep -o '[^<>]*'
答案 3 :(得分:0)
如果您的数据与您显示的一致,则不需要外部程序。
while read line; do
line="${line#*user=<}" # Remove from left up to <
line="${line%%>*}" # Remove to right from >
echo $line
done < test_log