Bash sed或awk删除包括换行符在内的图案

Bash sed或awk删除包括换行符在内的图案,bash,awk,sed,text-processing,Bash,Awk,Sed,Text Processing,我有一个与stderr结合的日志文件,我正试图清除它。我可以分离并找到stderr的“污染”,但我正在努力解决一个小细节:删除一条新线 这是我尝试还原的单独标准输出: some message 1234556 more info foo bar 这是组合的stdout/stderr文件,我正试图消除stderr消息: some message 1234/some/path ERROR more info only 1 line though 556 more info foo bar 这

我有一个与stderr结合的日志文件,我正试图清除它。我可以分离并找到stderr的“污染”,但我正在努力解决一个小细节:删除一条新线

这是我尝试还原的单独标准输出:

some message 1234556
more info foo bar
这是组合的stdout/stderr文件,我正试图消除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

我认为这不会带来太多问题(只有两种,所以我可以运行多个不同的匹配(
ERROR
另一个_ERR
)。我也不关心使用哪个工具
sed
awk

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

要将修改添加到位,请添加
-i
标志,类似于
sed

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

对于-E和-z使用GNU:

$ sed -Ez 's:/some/path ERROR\n[^\n]+\n::g' file
some message 1234556
more info foo bar
如果要处理多个错误,只需在regexp中列出或分开:

$ 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
将下一行吞入图案空间即可

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

  • N
    将下一行追加到模式空间
  • 删除正斜杠后的所有内容(包括下一行)
  • N
    将下一行追加到模式空间
  • 删除所有换行符
这离OP使用
n
的尝试不远了

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

sed-E:a/(错误|另一个错误)/{N;s/\/./;N;s/\N//g;ba}'

  • 使用
    -E
    在参数中允许两种模式
  • 添加标签
    :a
  • ba
    只要在模式空间中找到并处理错误字符串,就返回到
    :a

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

您能否澄清以下几点:(1)您为什么会有这种交错输出?您是否将两个命令的输出发送到同一个文件?(2)
more info only
是否总是以空格开头?
$ sed -E -n '/ERROR/{s@/.*@@;h;n;n;H;n;H;x;s/\n//;p}' input.log
some message 1234556
more info foo bar