grep 未按预期工作

lac*_*der 3 grep regular-expression

给定一个文件“test.log”,其中包含以下内容:

line1 Patient 123 45566
line2 Patient 432
line3 Patient 234 456
line4 Patient 321
line5
Run Code Online (Sandbox Code Playgroud)

我正在尝试选择line 2line 4使用这种模式:

grep "Patient\s\d+\s" test.log
# but this works testing at https://rubular.com/
Run Code Online (Sandbox Code Playgroud)

不起作用,这也不起作用:

grep "Patient\s\d+\n" test.log
# but this works testing at https://regexr.com/47qd5
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

nxn*_*nev 6

1. 使用命名类或 PCRE

GNUgrep默认使用基本正则表达式 (BRE),但它也允许您使用扩展正则表达式 (ERE) 和 Perl 兼容的正则表达式 (PCRE)。

请注意,BRE 和 ERE 都不支持\s也不支持\d,但它们具有相似的功能。从man grep

最后,在括号表达式中预定义了某些命名的字符类,如下所示。它们的名称是不言自明的,分别是[:alnum:][:alpha:][:cntrl:][:digit:][:graph:][:lower:][:print:]、、、 和。例如,表示当前语言环境中数字和字母的字符类。在 C 语言环境和 ASCII 字符集编码中,这与. (请注意,这些类名中的方括号是符号名称的一部分,除了界定方括号表达式的方括号之外,还必须包含方括号。)大多数元字符在方括号表达式内会失去其特殊含义。要包含文字,请将其放在列表的第一位。同样,要包含文字,请将其放置在除开头以外的任何位置。最后,将其文字放在最后。[:punct:][:space:][:upper:][:xdigit:][[:alnum:]][0-9A-Za-z]]^-

例子:

$ grep -E '^[[:digit:]]+$' << 'EOF'
> foo
> 123
> bar
> EOF
123
Run Code Online (Sandbox Code Playgroud)

您还可以使用 PCRE,因为它支持\s\d

$ grep -P '^\d+$' << 'EOF'
> foo
> 123
> bar
> EOF
123
Run Code Online (Sandbox Code Playgroud)

2.\n不起作用

在 Unix 中,每个\n分隔一行grep打印与给定模式匹配的行在这种情况下,匹配\n本身没有意义。

您可以使用$来匹配行尾:

$ grep -E 'foo bar$' << 'EOF'
> foo
> foo bar
> foo bar baz
> EOF
foo bar
Run Code Online (Sandbox Code Playgroud)

或传递-z/--null-data选项来激活“多行”模式(您需要一些额外的解决方法来完全匹配您想要的):

$ grep -Poz '(?<=\n)?foo bar\n' << 'EOF'
> foo
> foo bar
> foo bar baz
> EOF
foo bar
Run Code Online (Sandbox Code Playgroud)

3.你的第一个例子并不符合你的想法

最后一个\s将匹配line 1andline 3而不是line 2and line 4

$ grep -P 'Patient\s\d+\s' << 'EOF'
> line1 Patient 123 45566
> line2 Patient 432
> line3 Patient 234 456
> line4 Patient 321
> line5
> EOF
line1 Patient 123 45566
line3 Patient 234 456
Run Code Online (Sandbox Code Playgroud)