使用 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 进行更新