我的日志文件包含多行单个日志输出,如下所示:
DEBUG : <line1>
<line2>
TRACE : <line11>
<line12>
<line13>
DEBUG : <line21>
<line22>
<line23>
TRACE : <line31>
<line32>
ERROR : <line41>
<line42>
TRACE : <line51>
<line52>
DEBUG : <line61>
<line62>
我必须从 TRACE 输出中清除它。
我用
sed -e "/^TRACE/,/^DEBUG\|^ERROR/d" <log.txt
...然后得到
DEBUG : <line1>
<line2>
<line22>
<line23>
<line42>
<line62>
Sed 删除包含范围,并且不在 TRACE 块之后打印 DEBUG 和 ERROR 行。 我用 sed 尝试了其他方法,但没有找到如何仅删除 TRACE 块。
Sed 非常好,但也许我应该使用另一个 Unix 实用程序...请建议。
这里有一种方法可以在 sed 中完成您想要的操作,尽管这是我通常使用 perl 的情况。这使用 sed 的“保留空间”来收集日志文件的每个部分,并在看到下一部分的开始时打印(或不打印)整个部分。
sed -n -e '/^\(TRACE\|DEBUG\|ERROR\)/ ! { H ; $!b } ; x ; /^\(DEBUG\|ERROR\)/ p'
但是,回答问题的主题,我认为不可能从范围中排除最后一行。
awk '/^TRACE/ {
while ( $0 !~ /^DEBUG/ || $0 !~ /^ERROR/ ) {
getline ;
if ( $0 ~ /^DEBUG/ || $0 ~ /^ERROR/ ) {
print $0 ;
next
}
}
}
{ print $0 }' FILENAME
AWK 来救援;-)(注意:它可以粘贴到一行。)
这提供了一种将输入拆分到不同位置的合理技术。 使用案例会很好,但如果您坚持将字符串锚定在行的开头,我认为这是不可能的。
#!/bin/sh 执行3>&1 执行4> /dev/null 执行5>&1 同时读取 -r 行;做 回显 $line | grep ^DEBUG >&3 && 执行 >&3 && 继续 回显 $line | grep ^TRACE >&4 && 执行 >&4 && 继续 回显 $line | grep ^错误 >&5 && 执行 >&5 && 继续 回显$行 完毕
您可以复制标签,仅删除其中第一个:
sed -E "s/^((DEBUG)|(ERROR)) : /\1 : \n\1 /" | \
sed "/^TRACE/,/^DEBUG\|^ERROR/d" | sed "s/^</\t</"
DEBUG :
DEBUG <line1>
<line2>
DEBUG <line21>
<line22>
<line23>
ERROR <line41>
<line42>
DEBUG <line61>
<line62>
最后一个 sed 命令只是为了更好的可读性,第一行留作练习。 :)
这是一个将 sed 的保留空间用作布尔值的解决方案:当且仅当保留空间为空时,才会输出当前行。
sed -e '/^TRACE/ h ; /^\(DEBUG\|ERROR\)/ { x ; s/.*// ; x } ; x ; /./ { x ; d } ; x'
其工作原理如下:
^TRACE
匹配,则将其放入保留空间,以便禁用输出(见下文)。^\(DEBUG\|ERROR\)
匹配,则清除保留空间,以便启用输出(见下文)。x ; /./ { x ; d } ; x
才会删除当前模式空间。由于没有使用-n
,如果模式空间没有被删除,就会输出。根据需要,保留空间被保留(对于块的其他行):正好执行 2 个 x
(因为 d
开始一个新的循环)。备注:
^\(TRACE\|DEBUG\|ERROR\)
不匹配,此解决方案也有效(仅删除 TRACE
块)。