使用grep或其他命令返回多行模式的行号

时间:2019-04-16 04:52:15

标签: linux awk sed grep less-unix

我正在使用less命令浏览一个非常大的文本日志文件(15 GB),并试图搜索多行模式,但是经过一番调查,less命令只能搜索单行模式。

是否可以使用grep或其他命令来返回多行模式的数字行?

日志的格式在十万次迭代中是这样的:

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或其他命令返回出现这三种行模式时的行号开头:

op_3b       : 001
ctrl_2b     : 00
ini_count   : 0

4 个答案:

答案 0 :(得分:4)

假设该模式在文件pattern中,如下所示:

$ cat pattern
op_3b       : 001
ctrl_2b     : 00
ini_count   : 0

然后,尝试:

$ awk '$0 ~ 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,否则请不要使用它。)

  • $0 ~ pat

    这告诉awk打印与模式匹配的任何记录。

    $0是当前记录的内容。 ~告诉awk在$0中的文本和pat中的正则表达式之间进行匹配。

    (如果pattern的内容中有任何正则表达式有效字符,我们将需要对其进行转义。您当前的示例中没有任何正则表达式有效字符,因此这不是问题。)

替代样式

某些人更喜欢使用不同的样式来定义awk变量:

$ awk -v RS=  -v pat="$(cat pattern)" '$0 ~ pat' logfile
Packet LP
op_3b       : 001
ctrl_2b     : 00
ini_count   : 0

工作原理相同。

显示行号

$ awk -F'\n' '$0 ~ pat{print "Line Number="n+1; print "Packet" $0} {n=n+NF-1}' RS='Packet'  pat="$(cat pattern)" logfile
Line Number=20
Packet LP
op_3b       : 001
ctrl_2b     : 00
ini_count   : 0

答案 1 :(得分:2)

这是我微不足道的尝试:

awk -v RS="" -v FS="\n" -v op=001 -v ctrl=00 -v ini=0 '$2~op&&$3~ctrl&&$4~ini' data.txt

答案 2 :(得分:1)

到目前为止,最好的方法是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在第一个匹配项后返回,如果您的模式出现多次,则可以将其删除。
  • -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是最好的方法。

答案 3 :(得分:0)

如果您的数据位于“ d”文件中,请尝试:

grep -nEA2 '^op_3b\s*:\s*001' d

编辑上面的001号作为关键字搜索