从日志文件中 Grep 一行中的模式并打印接下来的 n 行,直到下一个模式

从日志文件中 Grep 一行中的模式并打印接下来的 n 行,直到下一个模式

假设文件log.txt包含以下内容

[12] 03/31/21 08:33:30.080851 T(12581) _DBG message x 1
[12] 03/31/21 08:33:30.080851 T(34897) _DBG message y 1
[12] 03/31/21 08:33:31.241167 T(12344) _DBG message z 1
[12] 03/31/21 08:33:31.457612 T(34897) _DBG message y 2
                        test message line 2
                        test message line 3 
                        test message line 4 
[12] 03/31/21 08:33:31.78912 T(12344) _DBG message z 2
[12] 03/31/21 08:33:32.56341 T(34897) _DBG message y 3
[12] 03/31/21 08:33:33.12789 T(12581) _DBG message x 2
                        test message for x
[12] 03/31/21 08:33:33.78123 T(34897) _DBG message y 3
                        test message line 2
[12] 03/31/21 08:33:34.12342 T(12581) _DBG message x 3
[12] 03/31/21 08:33:34.56712 T(34897) _DBG message y 4

期望的输出应该是

[12] 03/31/21 08:33:30.080851 T(34897) _DBG message y 1
[12] 03/31/21 08:33:31.457612 T(34897) _DBG message y 2
                        test message line 2
                        test message line 3 
                        test message line 4 
[12] 03/31/21 08:33:32.56341 T(34897) _DBG message y 3
[12] 03/31/21 08:33:33.78123 T(34897) _DBG message y 3
                        test message line 2
[12] 03/31/21 08:33:34.56712 T(34897) _DBG message y 4

给定线程 ID,它应该打印属于该消息的行+接下来的几行。请注意,在所需的输出中,所有其他线程消息都将被删除。

我尝试了下面的 sed 命令,但它也打印下一行(这是不同的线程消息)

sed -n -e '/T(34897)/,/_DBG/ p' log.txt 

我尝试了其他 grep/awk/regex 命令,但无法完成此操作。请帮忙

答案1

$ awk -v t=34897 '/^\[/{f=($4=="T("t")")} f' file
[12] 03/31/21 08:33:30.080851 T(34897) _DBG message y 1
[12] 03/31/21 08:33:31.457612 T(34897) _DBG message y 2
                        test message line 2
                        test message line 3
                        test message line 4
[12] 03/31/21 08:33:32.56341 T(34897) _DBG message y 3
[12] 03/31/21 08:33:33.78123 T(34897) _DBG message y 3
                        test message line 2
[12] 03/31/21 08:33:34.56712 T(34897) _DBG message y 4

f每次看到以 开头的行时,上面都会设置一个“已找到”标志[。如果该行的第 4 个字段T(<target value>)设置f为 true (1),否则设置为 false (0)。当读取每一行时,如果f当时为 true,则打印当前行。

对于任何 awk 脚本,如果您希望以不同的格式查看它并减少对默认值的依赖,使其变得不那么简短和更清晰,您可以使用 GNU awk 漂亮地打印它(注意:它必须是 gawk,而不是某些其他 awk 变体)为awk -o- ...

$ awk -o- -v t=34897 '/^\[/{f=($4=="T("t")")} f' file
/^\[/ {
        f = ($4 == "T(" t ")")
}

f {
        print
}

答案2

使用这个 awk 脚本:

BEGIN {
  doprint = 0
  marker = "T("thread")"
}

$1 ~ /\[[0-9]+\]/ {
   if( $4 == marker ) {
      doprint = 1
   } else {
      doprint = 0
   }
}

doprint==1 { print }

如此调用:

$ awk -v thread="34897" -f 642963.awk input.txt
[12] 03/31/21 08:33:30.080851 T(34897) _DBG message y 1
[12] 03/31/21 08:33:31.457612 T(34897) _DBG message y 2
                        test message line 2
                        test message line 3
                        test message line 4
[12] 03/31/21 08:33:32.56341 T(34897) _DBG message y 3
[12] 03/31/21 08:33:33.78123 T(34897) _DBG message y 3
                        test message line 2
[12] 03/31/21 08:33:34.56712 T(34897) _DBG message y 4

答案3

我们首先定义一些辅助变量来协助制定基于字段的正则表达式。

# definition of a unit space
_s_='[:space:]'

# regex for a space char and nonspace char
s="[$_s_]" S="[^$_s_]"

# a field is a run of nonspaces followed by a run of spaces
F="$S\{1,\}$s\{1,\}"

   id=34897

sed -ne ":top
  /^\[$S*$s$s*\($F\)\{2\}T($id)$s/{
    :nxt
      p;n
    /^$s/b nxt
    b top
  }
" file

相关内容