我似乎无法使其工作。GNU sed文档说要对管道进行转义,但这是行不通的,使用没有转义的直管也不行。添加括号没有区别。
$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat|dog/Bear/g'
cat
dog
pear
banana
cat
dog
$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat\|dog/Bear/g'
cat
dog
pear
banana
cat
dog
我似乎无法使其工作。GNU sed文档说要对管道进行转义,但这是行不通的,使用没有转义的直管也不行。添加括号没有区别。
$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat|dog/Bear/g'
cat
dog
pear
banana
cat
dog
$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat\|dog/Bear/g'
cat
dog
pear
banana
cat
dog
Answers:
默认情况下,sed
使用POSIX基本正则表达式,其中不包含|
交替运算符。许多版本的sed
,包括GNU和FreeBSD,都支持切换到扩展正则表达式,它们确实包含|
交替。这样做的方式各不相同:GNU sed使用-r
,而FreeBSD,NetBSD,OpenBSD和OS X sed使用-E
。其他版本几乎根本不支持它。您可以使用:
echo 'cat dog pear banana cat dog' | sed -E -e 's/cat|dog/Bear/g'
它将在那些BSD系统和sed -r
GNU上运行。
GNU sed
似乎完全没有文档,但是对的工作支持-E
,因此,如果您有一个局限于上述内容的多平台脚本,那么这是您的最佳选择。由于没有记录,因此您可能根本无法依靠它。
注释指出BSD版本也支持-r
作为未记录的别名。今天的OS X仍然没有,我可以使用的旧版NetBSD和OpenBSD机器也没有,但是NetBSD 6.1可以。我可以普遍达到的商业Unices却没有。因此,所有可移植性问题在这一点上都变得非常复杂,但是简单的答案是,awk
如果需要的话,切换到任何地方使用ERE。
-E
gnu.org/software/sed/manual/sed.html#index-_002dE。
做到这一点的便携式方法(更有效的方法)是使用地址。你可以这样做:
printf %s\\n cat dog pear banana cat dog |
sed -e '/cat/!{/dog/!b' -e '};cBear'
这样,如果该行不包含字符串cat且不包含该字符串dog sed
b
超出了脚本范围,则自动打印其当前行并拉入下一行以开始下一个循环。因此,它不执行下一条指令-在此示例中,该指令c
将整行挂起以读取Bear,但它可以执行任何操作。
可能还值得注意的是!b
,该sed
命令后面的任何语句只能在包含字符串dog
或cat
- 的行上匹配,因此您可以执行进一步的测试,而不会遇到不匹配的行的危险-这意味着您现在可以应用规则也只有一个或另一个。
但这是下一个。这是上面命令的输出:
###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear
您还可以通过反向引用可移植地实现查找表。
printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ cat dog /;x
};G;s/^\(.*\)\n.* \1 .*/Bear/;P;d'
设置此简单示例案例需要做很多工作,但从sed
长远来看,它可以使脚本更加灵活。
在第一行中,x
更改保留空间和模式空间,然后在将其变回之前将字符串<space>
cat <space>
dog<space>
插入保留空间x
。
从那时起,在接下来的每一行中,我G
保持在模式空间后面的空格,然后检查从该行的开始到我刚刚添加的换行符之间的所有字符是否都与该字符串后面的空格匹配。如果是这样,我将全部替换为Bear,如果没有,则不会造成任何伤害,因为我接下来P
仅将Rint填充到模式空间中第一个出现的换行符,然后将d
其全部删除。
###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear
当我说灵活的时候,我是说真的。这是更换猫与BrownBear和狗与BlackBear:
printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ 1cat Brown 2dog Black /;x
};G;s/^\(.*\)\n.* [0-9]\1 \([^ ]*\) .*/\2Bear/;P;d'
###OUTPUT###
BrownBear
BlackBear
pear
banana
BrownBear
BlackBear
您当然可以在查找表的内容上进行很多扩展-我从Greg Ubben的 Usenet电子邮件中获取了关于该主题的想法,当时他在90年代描述了他是如何用一条sed s///
语句构造一个简单的计算器的。
这里有一个技术,不使用任何具体的实施选项sed
(例如-E
,-r
)。除了将模式描述为单个正则表达式外cat|dog
,我们还可以运行sed
两次:
echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat/Bear/g' | sed 's/dog/Bear/g'
这确实是一个显而易见的解决方法,但值得分享。它自然地可以推广到两个以上的模式字符串,尽管很长sed
的s看起来不太好。
我经常使用sed -i
(在所有实现中都起作用)对文件进行更改。在这里,可以很好地合并一长串模式字符串,因为每个临时结果都保存到文件中:
for pattern in cat dog owl; do
sed -i "s/${pattern}/Bear/g" myfile
done
-r
选项,作为-E
与GNU sed兼容的同义词。OpenBSD和OS Xsed -E
将转义的管道解释为文字管道,而不是交替运算符。这是 NetBSD手册页的有效链接,而这是 OpenBSD使用十年之久的链接。