使用 AWK(或 SED)获取字符串之间的文本 - 包括 START 字符串但排除 END 字符串

Use AWK (or SED) to get text between strings - include START string but exclude END string

我正在尝试使用 AWK(或 SED 或两者的组合)来解析包含特定字符串“Info:AgentSession”的日志文件。 我想包含包含“Info:AgentSession”的 START 字符串的行,但不包含 END 字符串行,这将是“[2015-”。

这是 CentOS 服务器上的文本日志文件的片段:


[2015-03-30 12:23:10.999] [124] [Info:AgentSession] Handling Agent message for PieraC 
Request: ReceiveReady
Action: DoNotDisturb

[2015-03-30 12:23:11.000] [124] [Info:AgentSession] Sending agent message to PieraC 
Response: ReceiveReady
RequestId: 
Status: Ok
Message: 
IsReady: False

[2015-03-30 12:23:11.000] [49] [Info:Database] (BZ2411) (SqlTaskWorker.ProcessTasks) Attempting to run task. Thread: SqlTaskWorker-37. StartTime: 1/1/0001 12:00:00 AM. ConnectionTimeout: 15. ConnectionState: Open.

[2015-03-30 12:23:11.501] [111] [Info:Dialer] Sending Dialer message
Action: UsmCommand
Command: Transfer
IsTransfered: False

[2015-03-30 12:23:11.502] [111] [Info:AgentSession] Sending agent message to MatthewW 
ActivityState: Wrapup
IsReady: False
IsSipRegistered: True

[2015-03-30 12:23:11.502] [79] [Info:Database] (BZ2411) (SqlTask.Execute) Attempting to start. Thread: SqlTaskWorker-67. 

[2015-03-30 12:23:16.207] [124] [Info:AgentSession] Sending agent message to PieraC 
Response: NonQuery
Status: Ok
Message: Query sent successfully

[2015-03-30 12:23:16.207] [88] [Info:Database] (BZ2411) (SqlTaskWorker.ProcessTasks) Attempting to run task. Thread: SqlTaskWorker-76. 
[2015-03-30 12:23:16.207] [88] [Info:Database] (BZ2411) (SqlTask.Execute) Attempting to start. Thread: SqlTaskWorker-76. 
[2015-03-30 12:23:16.208] [88] [Info:Database] (BZ2411) (SqlNonQueryTask.ExecuteCommand) Attempting to start. Thread: SqlTaskWorker-76. 
[2015-03-30 12:23:16.268] [124] [Info:AgentSession] Handling Agent message for PieraC 
Request: CallAction
CallDisposition: 


当我运行以下命令时:


awk '/Info:AgentSession/ {flag=1;next} /\[2015-/{flag=0} flag {print}' test.log


我得到以下输出:


Request: ReceiveReady
Action: DoNotDisturb

Response: ReceiveReady
RequestId:
Status: Ok
Message:
IsReady: False

ActivityState: Wrapup
IsReady: False
IsSipRegistered: True

Response: NonQuery
Status: Ok
Message: Query sent successfully

Request: CallAction
CallDisposition:


但是我想要这个输出,包括“Info:AgentSession”的 START 字符串,所以实际上最终看起来像这样(省略日志的所有其他部分引用 START 字符串,使用 DATE 字符串“[2015-”的开头作为 END 字符串):


[2015-03-30 12:23:10.999] [124] [Info:AgentSession] Handling Agent message for PieraC 
Request: ReceiveReady
Action: DoNotDisturb

[2015-03-30 12:23:11.000] [124] [Info:AgentSession] Sending agent message to PieraC 
Response: ReceiveReady
RequestId: 
Status: Ok
Message: 
IsReady: False

[2015-03-30 12:23:11.502] [111] [Info:AgentSession] Sending agent message to MatthewW 
ActivityState: Wrapup
IsReady: False
IsSipRegistered: True


[2015-03-30 12:23:16.207] [124] [Info:AgentSession] Sending agent message to PieraC 
Response: NonQuery
Status: Ok
Message: Query sent successfully

[2015-03-30 12:23:16.268] [124] [Info:AgentSession] Handling Agent message for PieraC 
Request: CallAction
CallDisposition: 


这可能与简单的 AWK 或 SED 命令有关吗?

你可以使用一个简单的循环 sed:

sed -n '/Info:AgentSession/{:a;p;n;/^$/!ba;p}' input.file

该命令搜索包含模式 /Info:AgentSession/ 的行。如果出现这样一行,则执行大括号 {} 之间的以下块。在该块中,我们为循环定义了一个开始标签,简称为 :a。然后我们打印当前行 p,从输入 n 获取下一行并检查它是否为空 /^$/。如果行不为空!,我们退回到循环的开始ba。否则,我们将该空行打印为记录分隔符,并在下一行输入中再次开始搜索 /Info:AgentSession/

使用 -n 命令行选项抑制其他行的输出。

输出:

[2015-03-30 12:23:10.999] [124] [Info:AgentSession] Handling Agent message for PieraC 
Request: ReceiveReady
Action: DoNotDisturb
[2015-03-30 12:23:11.000] [124] [Info:AgentSession] Sending agent message to PieraC 
Response: ReceiveReady
RequestId: 
Status: Ok
Message: 
IsReady: False

[2015-03-30 12:23:11.502] [111] [Info:AgentSession] Sending agent message to MatthewW 
ActivityState: Wrapup
IsReady: False
IsSipRegistered: True

[2015-03-30 12:23:16.207] [124] [Info:AgentSession] Sending agent message to PieraC 
Response: NonQuery
Status: Ok
Message: Query sent successfully

[2015-03-30 12:23:16.268] [124] [Info:AgentSession] Handling Agent message for PieraC 
Request: CallAction
CallDisposition: 

另一种方法是像这样使用 awk

awk -F'\n' ' ~ /Info:AgentSession/' RS='\n\n' ORS='\n\n' input.file

我将输入和输出分隔符定义为两个换行符的序列。字段分隔符是单个换行符。如果我们记录的第一个字段包含模式 Info:AgentSession 我们打印整个记录。


顺便说一下,上面的 sed 命令也可以不用 -n 选项来写:

sed '/Info:AgentSession/{:a;n;/^$/!ba;p};d' input.file

在这种情况下,我们正在搜索包含 /Info:AgentSession/ 的行,如果找到这样的行,则在大括号之间执行以下块。我们定义一个标签 :a,打印当前行并从输入 n 获取下一行。只要 /^$/! 后面有非空行,我们就会回到循环的开头 ba,否则我们会打印该空行作为记录分隔符 p。所有其他行都被删除 d.

使用awk:

awk '/^[[]/{f=0} /Info:AgentSession/{f=1} f' file

工作原理

awk 遍历每行输入。对于每一行,程序决定是将变量 f 设置为真 (1) 还是假 (0)。如果 f 为真,则打印该行。

  • /^[[]/{f=0}

    只要一行以 [ 开头,f 就会设置为 false。

  • /Info:AgentSession/{f=1}

    如果该行包含字符串 Info:AgentSession,则先前的命令被覆盖并且 f 设置为 true。

  • f

    如果 f 为真,则 awk 打印该行。

    以上是 shorthand for f{print [=24=]} 其中,在 awk 中,[=25=] 表示整行。

这可能适合您 (GNU sed):

sed -n '/Info:AgentSession/,/^$/p' file