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

Posted

技术标签:

【中文标题】使用 AWK(或 SED)获取字符串之间的文本 - 包括 START 字符串但不包括 END 字符串【英文标题】:Use AWK (or SED) to get text between strings - include START string but exclude END string 【发布时间】:2015-06-04 01:16:50 【问题描述】:

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

这是 CentOS 服务器上文本日志文件的 sn-p:

[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 命令有关吗?

【问题讨论】:

print 命令添加到第一个块。 【参考方案1】:

使用awk

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

工作原理

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

/^[[]/f=0

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

/Info:AgentSession/f=1

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

f

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

以上是fprint $0 的简写,在awk 中,$0 表示整行。

【讨论】:

完美! - 感谢您的解决方案 + 解释@John1024【参考方案2】:

您可以使用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' '$1 ~ /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

【讨论】:

感谢@hek2mgl。我试过这个,但我只得到第一行的输出,而不是表达式之间需要的所有行。例如,我只得到如下一行:[2015-03-30 12:23:16.207] [124] [Info:AgentSession] Sending agent message to PieraC [2015-03-30 12:23:16.268] [124] [Info:AgentSession] Handling Agent message for PieraC 每行下方没有任何部分。 是的,有一个小错误。 (我用n 替换了N)。它现在应该可以工作了。 是的!这现在也适用于我,再次感谢 hek2mgl! @ChrisCharles 还要检查我添加的awk 替代方案。 awk 处理更直观,因为它将块简单地定义为记录。【参考方案3】:

这可能对你有用(GNU sed):

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

【讨论】:

以上是关于使用 AWK(或 SED)获取字符串之间的文本 - 包括 START 字符串但不包括 END 字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sed 或 awk 命令用变量(变量保存 Unix 脚本)查找和替换文本

从不同文件中查找相关文本并使用 sed 或 awk 或 grep 进行更新

使用 sed 或 awk 在特定行号处插入一行

使用 sed 或 awk 在特定行号处插入一行

Linux的awk、grep、sed工具,实现文本查找、编辑 、格式化

如何使用 sed 或 awk 正确查找和替换多行文本?