【问题标题】:Awk: print between patterns in the same line and reverse the order of matched stringawk:在同一行中的模式之间打印并反转匹配字符串的顺序
【发布时间】:2020-07-08 10:39:30
【问题描述】:

我有一个应用程序服务的日志文件,我正在尝试提取其中一个子进程转储的堆栈跟踪。堆栈跟踪的模式与通常的日志文件完全不同。

通常的 webapp 日志文件条目:

2020-03-26 08:31:05.000 : INFO : (18582) : (SERVICE) : MSG_1234 : Process id 98765. Standard output and error:

堆栈跟踪示例:

7f318820d000-7f318a106000 rwxp 00000000 00:00 0                          [stack:10002]
7f318a106000-7f318a107000 ---p 00000000 00:00 0 

我需要提取堆栈跟踪,这是我能够做到的。堆栈跟踪的问题在于它们以相反的顺序转储。每个转储的块都是有序的,但是这些块以相反的顺序转储。

这是我如何提取块的示例(注意:开始和停止模式在同一行):

echo "STOP message START
five
six
STOP message START
three
four
STOP message START
one
two
STOP message" | awk '/START/ {flag=1; next} flag; /STOP/ {flag=0}'

这是输出:

five
six
three
four
one
two
STOP message

虽然,我想得到这个:

one
two
three
four
five
six

我可以忍受最后一个匹配的“停止消息”,但我需要按顺序排列块。

【问题讨论】:

    标签: sorting parsing awk


    【解决方案1】:

    如果您以此开始对每个块和每个块中的行进行编号,然后您可以使用sort 按您喜欢的方式对行进行排序,然后删除您使用cut 添加的数字:

    $ awk -v OFS='\t' '/STOP/{lineNr=0} lineNr{print blockNr, lineNr++, $0} /START/{blockNr++; lineNr=1}' file
    1       1       five
    1       2       six
    2       1       three
    2       2       four
    3       1       one
    3       2       two
    

    例如:

    $ awk -v OFS='\t' '/STOP/{lineNr=0} lineNr{print blockNr, lineNr++, $0} /START/{blockNr++; lineNr=1}' file |
        sort -k1,1nr -k2,2n
    3       1       one
    3       2       two
    2       1       three
    2       2       four
    1       1       five
    1       2       six
    
    $ awk -v OFS='\t' '/STOP/{lineNr=0} lineNr{print blockNr, lineNr++, $0} /START/{blockNr++; lineNr=1}' file |
        sort -k1,1nr -k2,2n | cut -f3-
    one
    two
    three
    four
    five
    six
    

    【讨论】:

    • 这是有效的。我唯一需要更改的是 sort 语法从 sort -n -k1,1r -k2,2sort -k1,1nr -k2,2n。出于某种原因,它没有正确排序数字字段>9,一开始只有一个-n。你知道为什么吗?
    • 不,但我发现sort 选项语法非常不直观,所以也许这就是您在使用特定键字段编号时必须编写命令的方式,idk。我会更新我的答案,因为我们知道这是可行的。
    • 嗯,seq 15 | sort -k1,1 的快速测试结果表明,当您向键添加任何选项(例如 -k1,1r)时,它会覆盖所有全局选项。所以seq 15 | sort -n -k1,1 有效,但seq 15 | sort -n -k1,1r 无效,您必须改用seq 15 | sort -k1,1rn。这很烦人。
    • 您只需按照打印这些行所需的任何顺序匹配开始/结束标记。如果您执行/START/{f=1} f{print} /STOP/{f=0},那么当看到包含START 和STOP 的行并打印它们时,就会设置f。与/STOP/{f=0} /START/{f=1} f{print}/STOP/{f=0} f{print} /START/{f=1} 等中的每一个进行比较 - 只需根据您要打印的开始/停止行适当地命令 3 个块来设置/清除f
    • 不确定我是否理解这个问题,但我认为答案是否定的?你可能想多了,这很简单——当你试图在开始/结束标记之间打印文本时,你总是有 3 个代码块:块 A 设置“找到”标志,块 B 在设置标志时打印当前行, 并阻止 C 清除标志。只需以任何顺序排列这 3 个块,即可为包含开始/结束标记的行提供所需的输出:A B C 或 A C B 或 B C A 或其他。
    猜你喜欢
    • 2019-04-02
    • 1970-01-01
    • 2015-04-14
    • 1970-01-01
    • 2022-01-16
    • 2017-07-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-03
    相关资源
    最近更新 更多