我正在为构建输出做一个解析器,我想强调不同颜色的不同模式。例如,我想做:
sed -e "s|\(Error=errcode1\)|<red>\1<_red>|" \
-e "s|\(Error=errcode2\)|<orange>\1<_orange>|" \
-e "s|\(Error=.*\)|<blue>\1<_blue>|"
(因此它突出了errcode1为红色,errcode2为橙色,其他任何为蓝色)。这个问题是Error=errcode1
匹配第一个和第三个表达式,这将导致<red><blue>Error=errcode1<_red><_blue>
...有没有办法告诉sed只匹配第一个表达式,如果它匹配,不要尝试以下表达式?
注意,sed命令实际上是从非常不稳定的文件自动生成的,所以我想要一个通用的解决方案,我不必警告模式是否冲突......
答案 0 :(得分:4)
让我们从一个更简单的例子开始来说明问题。在下面的代码中,执行两个替换:
$ echo 'error' | sed 's/error/error2/; s/error/error3/'
error32
如果我们想要跳过第二个,如果第一个成功,我们可以使用“test”命令,如果前一个替换成功,则分支。如果我们在t
之后没有提供标签,它会跳到最后,跳过所有剩余的命令:
$ echo 'error' | sed 's/error/error2/; t; s/error/error3/'
error2
如果要在第一次成功替换后停止,请在每个替换命令后放置t
命令。
假设我们想要跳过第二个而不是第三个替换,如果第一个成功的话。在这种情况下,我们需要为t
命令提供标签:
$ echo 'error' | sed 's/error/error2/; ta; s/error/error3/; :a; s/error/error4/'
error42
在上文中,:a
定义了标签a
。如果前面的ta
命令成功,则命令a
分支到标签s
。
上面的代码在GNU sed中测试过。我被告知BSD sed不接受;
作为标签后的命令分隔符。因此,在BSD / macOS上,尝试:
echo 'error' | sed -e 's/error/error2/' -e ta -e 's/error/error3/' -e :a -e 's/error/error4/'
答案 1 :(得分:0)
您可以将布尔逻辑应用于与|
,&
和!
的匹配。
(不确定语法是否与您的系统兼容,因此您可能需要添加更多反斜杠)
"s|\(Error=\(.*&!errcode1&!errcode2\)\)|<blue>\1<_blue>|"
sed
可以使用任何字符作为分隔符,因此以下所有表达式都是等效的:
"s/foo/bar/"
"s:foo:bar:"
"s|foo|bar|"
"s#foo#bar#"
此外,如果您在基于Unix的系统上使用bash
,则可以使用shell变量(如果您从脚本运行此变量)(因为您的模式附带"
并且不是'
,而是存在差异。
PREFIX="Error="
TARGET_1="errorcode1"
TARGET_2="errorcode2"
SUB_1="<red>\1<_red>"
SUB_2="<orange>\1<_orange>"
SUB_3="<blue>\1<_blue>"
sed -e "s|\($PREFIX$TARGET_1\)|$SUB_1|" \
-e "s|\($PREFIX$TARGET_2\)|$SUB_2|" \
-e "s|\($PREFIX\(.*&!$TARGET_1&!$TARGET_2\)\)|$SUB_3|" \
答案 2 :(得分:0)
如果其他错误代码遵循命名方案errcodeN,则可以否定1,2:
sed -e "s|\(Error=errcode1\)|<red>\1<_red>|" \
-e "s|\(Error=errcode2\)|<orange>\1<_orange>|" \
-e "s|\(Error=errcode[^12]\)|<blue>\1<_blue>|"
如果代码超过了数字9:[^12]+
答案 3 :(得分:0)
这对于sed来说不是一个好的应用程序,你应该使用awk代替。你没有提供任何样本输入/输出来测试,所以这显然没有经过测试,但你做的是这样的:
awk '
BEGIN {
colors["errorcode1"] = "red"
colors["errorcode2"] = "orange"
colors["default"] = "blue"
}
match($0,/(.*Error=)([[:alnum:]]+)(.*)/,a) {
code = a[2]
color = (code in colors ? colors[code] : colors["default"])
$0 = sprintf("%s<%s>%s<_%s>%s", a[1], color, code, color, a[3])
}
{ print }
'
以上使用GNU awk为第3个arg匹配(),它是其他awk的小调整。