16

基本上我想做的是解析文件中的行并返回用户名。用户名总是用 < 和 > 括起来,所以我想使用正则表达式来匹配 < 之前(包括)之前的所有内容以及之后(包括)> 之后的所有内容,然后反转我的匹配。我知道 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

但是,在运行我的脚本时,没有返回任何内容,尽管当我用逆匹配的正则表达式测试正则表达式时,它完全符合我的要求。我究竟做错了什么?

4

4 回答 4

28

试试这个 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.
于 2013-03-01T17:08:07.593 回答
6

实际上,我也喜欢@Kent 的回答,而且它是正确的,但有时很难记住“grep”实用程序的“-Po”之类的开关。通常,如果您不记得确切的标志,您可能会要求 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

正如我们所看到的,还有其他可能的选项,例如"-E"

于 2016-07-13T13:23:47.247 回答
1

我实际上更喜欢@Kent 的回答,但是如果我们可以假设最新版本的 grep 并且您想避免基于 perl 的正则表达式,您仍然可以直接提取用户名:

echo $line | grep -o '<[^>]*>' | grep -o '[^<>]*'
于 2013-03-01T17:13:50.647 回答
0

如果您的数据与您显示的一样一致,则您实际上并不需要外部程序。

while read line; do
    line="${line#*user=<}"  # Remove from left up to <
    line="${line%%>*}"      # Remove to right from >
    echo $line
done < test_log
于 2013-03-01T19:18:43.783 回答