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
我认为问题不大(只有两种,所以我可以 运行 多个不同的匹配项(ERROR
和 ANOTHER_ERR
)。我也不关心使用哪个工具 sed
或 awk
...
您可以使用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,它可能不是最佳选择。
我有一个与 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
我认为问题不大(只有两种,所以我可以 运行 多个不同的匹配项(ERROR
和 ANOTHER_ERR
)。我也不关心使用哪个工具 sed
或 awk
...
您可以使用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,它可能不是最佳选择。