【问题标题】:sed or awk to remove pattern including newlinesed 或 awk 删除包含换行符的模式
【发布时间】:2019-08-31 09:05:24
【问题描述】:

我有一个日志文件,它与我试图清理的 stderr 结合在一起。我可以隔离并找到stderr“污染”,但我正在努力处理一个小细节:删除换行符

这是我尝试恢复的单独标准输出:

some message 1234556
more info foo bar

这是我试图摆脱 stderr 消息的组合 stdout/stderr 文件:

some message 1234/some/path ERROR
  more info only 1 line though
556
more info foo bar

所以这是我要删除的文本:

/some/path ERROR
more info only 1 line though

包括换行符,以便恢复单独的标准输出。

我打电话:

# get rid of the line AFTER the stderr start
sed -i".bak" -e '/ERROR/{n;d}' *.log

# get rid of the start of stderr
sed -i".bak" -r 's/\/some\/path.*ERROR//' *.log

不幸的是,现在的输出是:

some message 1234
556
more info foo bar

注意,stderr 消息的插入点可以是任意的(在一行的中间或开头,任何地方)。我唯一能假设的是 stderr 是一个两行代码,它以 /some/path 开头并包含一个错误标识符(ERROR 或其他内容)。此外,可能会有多个后续的 stderr 消息,例如:

some message 1234/some/path ERROR
  more info only 1 line though
/some/path ANOTHER_ERR
  more info only 1 line though
556
more info foo bar

我认为这不会造成太大问题(只有 2 种,所以我可以运行多个不同的匹配项(ERRORANOTHER_ERR))。我也不关心使用哪个工具sedawk...

【问题讨论】:

  • 你能澄清几件事吗:(1)你怎么会有这样的交错输出?您是否将两个命令的输出发送到同一个文件? (2) more info only 总是以空格开头吗?

标签: bash awk sed text-processing


【解决方案1】:

您可以使用强大的段落模式选项perl-00 命令行选项打开段落 slurp 模式,这意味着 Perl 逐段读取文本, 而不是逐行(段落是两个或多个换行符之间的文本。)

perl -00 -pe 's/\/.*(ERROR|ANOTHER_ERR)\n.*\n//g' file

要就地添加修改,请添加-i 标志,类似于sed

perl -00 -pi -e 's/\/.*(ERROR|ANOTHER_ERR)\n.*\n//g' file

【讨论】:

    【解决方案2】:

    对于 -E 和 -z 使用 GNU sed:

    $ sed -Ez 's:/some/path ERROR\n[^\n]+\n::g' file
    some message 1234556
    more info foo bar
    

    如果您有多个错误要处理,那么只需在正则表达式中列出它们或分隔:

    $ cat file
    some message 1234/some/path ERROR
      more info only 1 line though
    /some/path ANOTHER_ERR
      more info only 1 line though
    556
    more info foo bar
    
    $ sed -Ez 's:/some/path (ERROR|ANOTHER_ERR)\n[^\n]+\n::g' file
    some message 1234556
    more info foo bar
    

    或者,使用 GNU awk 进行多字符 RS:

    $ awk -v RS='/some/path ERROR\n[^\n]+\n' -v ORS= '1' file
    some message 1234556
    more info foo bar
    

    或者如果您愿意:

    $ awk -v RS='^$' -v ORS= '{gsub("/some/path ERROR\n[^\n]+\n","")}1' file
    some message 1234556
    more info foo bar
    

    【讨论】:

      【解决方案3】:

      另一个没有-z 选项的 sed 解决方案:

      $ sed -E -n '/ERROR/{s@/.*@@;h;n;n;H;n;H;x;s/\n//;p}' input.log
      some message 1234556
      more info foo bar
      

      【讨论】:

        【解决方案4】:

        对于一些基本的 sed 来说似乎是完美的。只需使用N 将下一行吞入模式空间。

        sed '/ERROR/{N;s/\/.*//;N;s/\n//g}' input.log

        • N 将下一行追加到模式空间
        • 删除正斜杠后的所有内容(包括下一行)
        • N 将下一行追加到模式空间
        • 删除所有换行符

        这与 OP 对n 的尝试相距不远。

        要将其扩展到后面的示例,您需要回到开头查看 N 命令是否将更多错误字符串带入模式空间:

        sed -E ':a /(ERROR|ANOTHER_ERR)/{N;s/\/.*//;N;s/\n//g;b a}'

        • 使用-E 允许括号中有两个模式
        • 添加标签:a
        • 每当发现并处理模式空间中的错误字符串时,b a 就会分支回:a

        我更喜欢避开sed -z。它将整个文件读入模式空间,因此如果这个日志文件很长,或者如果您将活动流通过管道传输到 sed,它可能不是最佳选择。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-16
          • 1970-01-01
          • 1970-01-01
          • 2020-04-25
          • 1970-01-01
          • 2019-12-01
          相关资源
          最近更新 更多