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

问题描述 投票:2回答:4

我有一个日志文件,它与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

包括换行符,以便恢复单独的stdout。

我打电话:

# 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 ...

bash awk sed text-processing
4个回答
2
投票

对于一些基本的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允许两个模式的parens
  • 添加标签:a
  • 只要找到并处理了模式空间中的错误字符串,b a就会回到:a

我宁愿避免使用sed -z。它会将整个文件读入模式空间,因此如果此日志文件很长,或者您正在将活动流传输到sed,它可能不是最佳选择。


4
投票

您可以使用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

3
投票

使用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

1
投票

没有-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
© www.soinside.com 2019 - 2024. All rights reserved.