sed 或 awk 删除包括换行符的模式

sed or awk to remove pattern including newline

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

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

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

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

您可以使用perl强大的段落模式选项。 -00 命令行选项打开段落模式,意味着 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

使用 GNU sed for -E 和 -z:

$ 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

另一个没有-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

对于一些基本的 sed 来说似乎是完美的。只需使用 N 到 gulp 下一行进入模式 space.

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

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

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

为了将其扩展到后面的示例,您可以分支回到开始,查看 N 命令是否将更多错误字符串带入模式 space:

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

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

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