使用 grep 或其他命令 return 多行模式的行号
Using grep or other command to return the line number of a multiline pattern
我正在使用 less
命令浏览一个非常大的文本日志文件 (15 GB) 并试图搜索多行模式,但经过一番调查后,less
命令只能搜索单线图案。
有没有办法使用 grep
或其他命令来 return 多行模式的数字行?
十万次迭代的日志格式是这样的:
Packet A
op_3b : 001
ctrl_2b : 01
ini_count : 5
Packet F
op_3b : 101
ctrl_2b : 00
ini_count : 4
Packet X
op_3b : 010
ctrl_2b : 11
ini_count : 98
Packet CA
op_3b : 100
ctrl_2b : 01
ini_count : 5
Packet LP
op_3b : 001
ctrl_2b : 00
ini_count : 0
Packet ZZ
op_3b : 111
ctrl_2b : 01
ini_count : 545
Packet QEA
op_3b : 111
ctrl_2b : 11
ini_count : 0
我想要得到的是 grep
或其他一些命令 return 当这三行模式出现时行号的开始:
op_3b : 001
ctrl_2b : 00
ini_count : 0
假设模式在文件 pattern
中是这样的:
$ cat pattern
op_3b : 001
ctrl_2b : 00
ini_count : 0
然后,尝试:
$ awk '[=11=] ~ pat' RS= pat="$(cat pattern)" logfile
Packet LP
op_3b : 001
ctrl_2b : 00
ini_count : 0
工作原理
RS=
这会将记录分隔符 RS
设置为空字符串。这告诉 awk 使用空行作为记录分隔符。
pat="$(cat pattern)"
这告诉 awk 创建一个 awk 变量 pat
,其中包含文件 pattern
.
的内容
如果您的 shell 是 bash,那么此命令的一种稍微更有效的形式是 pat="$(<pattern)"
。 (除非你确定你的shell是bash,否则不要使用它。)
[=21=] ~ pat
这告诉 awk 打印任何匹配模式的记录。
[=22=]
是当前记录的内容。 ~
告诉 awk 在 [=22=]
中的文本和 pat
.
中的正则表达式之间进行匹配
(如果 pattern
的内容有任何正则表达式活动字符,我们需要将它们转义。您当前的示例没有任何所以这不是问题。)
替代风格
有些人更喜欢用不同的风格来定义 awk 变量:
$ awk -v RS= -v pat="$(cat pattern)" '[=12=] ~ pat' logfile
Packet LP
op_3b : 001
ctrl_2b : 00
ini_count : 0
这也是一样的。
显示行号
$ awk -F'\n' '[=13=] ~ pat{print "Line Number="n+1; print "Packet" [=13=]} {n=n+NF-1}' RS='Packet' pat="$(cat pattern)" logfile
Line Number=20
Packet LP
op_3b : 001
ctrl_2b : 00
ini_count : 0
这是我的尝试:
awk -v RS="" -v FS="\n" -v op=001 -v ctrl=00 -v ini=0 '~op&&~ctrl&&~ini' data.txt
到目前为止最好的方法是 John1024 使用 awk
的方法,因为你可以一次性完成,如果你真的想寻求 grep
解决方案,你可以使用:
$ grep -m 1 -zoP 'Packet\s*[^\s]*\s*(?=op_3b\s*:\s*001\s*ctrl_2b\s*:\s*00\sini_count\s*:\s*0)' file
Packet LP
备注:
-m 1
将在第一次匹配后进行 grep return,如果您的模式出现多次,您可以将其删除。
-z
允许多行模式,因为它启用 ASCII NUL
字符而不是正常的 EOL
-o
只显示结果匹配而不是整个文件
-P
激活 perl 正则表达式
如果你想要行号:
grep -n -f <(grep -m 1 -zoP 'Packet\s*[^\s]*\s*(?=op_3b\s*:\s*001\s*ctrl_2b\s*:\s*00\sini_count\s*:\s*0)' file) file
21:Packet LP
但是您需要执行 2 次传递,因此对于 15GB 的文件 awk
是最佳方法。
如果您的数据在 'd' 文件中,请尝试:
grep -nEA2 '^op_3b\s*:\s*001' d
编辑上面的数字 001
作为您的关键搜索
我正在使用 less
命令浏览一个非常大的文本日志文件 (15 GB) 并试图搜索多行模式,但经过一番调查后,less
命令只能搜索单线图案。
有没有办法使用 grep
或其他命令来 return 多行模式的数字行?
十万次迭代的日志格式是这样的:
Packet A
op_3b : 001
ctrl_2b : 01
ini_count : 5
Packet F
op_3b : 101
ctrl_2b : 00
ini_count : 4
Packet X
op_3b : 010
ctrl_2b : 11
ini_count : 98
Packet CA
op_3b : 100
ctrl_2b : 01
ini_count : 5
Packet LP
op_3b : 001
ctrl_2b : 00
ini_count : 0
Packet ZZ
op_3b : 111
ctrl_2b : 01
ini_count : 545
Packet QEA
op_3b : 111
ctrl_2b : 11
ini_count : 0
我想要得到的是 grep
或其他一些命令 return 当这三行模式出现时行号的开始:
op_3b : 001
ctrl_2b : 00
ini_count : 0
假设模式在文件 pattern
中是这样的:
$ cat pattern
op_3b : 001
ctrl_2b : 00
ini_count : 0
然后,尝试:
$ awk '[=11=] ~ pat' RS= pat="$(cat pattern)" logfile
Packet LP
op_3b : 001
ctrl_2b : 00
ini_count : 0
工作原理
RS=
这会将记录分隔符
RS
设置为空字符串。这告诉 awk 使用空行作为记录分隔符。pat="$(cat pattern)"
这告诉 awk 创建一个 awk 变量
的内容pat
,其中包含文件pattern
.如果您的 shell 是 bash,那么此命令的一种稍微更有效的形式是
pat="$(<pattern)"
。 (除非你确定你的shell是bash,否则不要使用它。)[=21=] ~ pat
这告诉 awk 打印任何匹配模式的记录。
中的正则表达式之间进行匹配[=22=]
是当前记录的内容。~
告诉 awk 在[=22=]
中的文本和pat
.(如果
pattern
的内容有任何正则表达式活动字符,我们需要将它们转义。您当前的示例没有任何所以这不是问题。)
替代风格
有些人更喜欢用不同的风格来定义 awk 变量:
$ awk -v RS= -v pat="$(cat pattern)" '[=12=] ~ pat' logfile
Packet LP
op_3b : 001
ctrl_2b : 00
ini_count : 0
这也是一样的。
显示行号
$ awk -F'\n' '[=13=] ~ pat{print "Line Number="n+1; print "Packet" [=13=]} {n=n+NF-1}' RS='Packet' pat="$(cat pattern)" logfile
Line Number=20
Packet LP
op_3b : 001
ctrl_2b : 00
ini_count : 0
这是我的尝试:
awk -v RS="" -v FS="\n" -v op=001 -v ctrl=00 -v ini=0 '~op&&~ctrl&&~ini' data.txt
到目前为止最好的方法是 John1024 使用 awk
的方法,因为你可以一次性完成,如果你真的想寻求 grep
解决方案,你可以使用:
$ grep -m 1 -zoP 'Packet\s*[^\s]*\s*(?=op_3b\s*:\s*001\s*ctrl_2b\s*:\s*00\sini_count\s*:\s*0)' file
Packet LP
备注:
-m 1
将在第一次匹配后进行 grep return,如果您的模式出现多次,您可以将其删除。-z
允许多行模式,因为它启用ASCII NUL
字符而不是正常的 EOL-o
只显示结果匹配而不是整个文件-P
激活 perl 正则表达式
如果你想要行号:
grep -n -f <(grep -m 1 -zoP 'Packet\s*[^\s]*\s*(?=op_3b\s*:\s*001\s*ctrl_2b\s*:\s*00\sini_count\s*:\s*0)' file) file
21:Packet LP
但是您需要执行 2 次传递,因此对于 15GB 的文件 awk
是最佳方法。
如果您的数据在 'd' 文件中,请尝试:
grep -nEA2 '^op_3b\s*:\s*001' d
编辑上面的数字 001
作为您的关键搜索