在 sed 中使用多个感叹号有什么意义?

在 sed 中使用多个感叹号有什么意义?

POSIX sed 文档说:

函数前面可以有一个或多个“!”字符,在这种情况下,如果地址不选择模式空间,则应应用该函数。第一个 '!' 之前应接受零个或多个 <blank> 字符特点。未指定 <blank> 字符是否可以跟在 '!' 后面字符,并且符合要求的应用程序不应遵循“!”带有 <blank> 字符的字符。

因此,使用任何 POSIX sed,我们可以:

sed -e '/pattern/!d' file

这与写作相同:

sed -e '/pattern/!!d' file

!!!dn感叹号仍然可以(用三个sed版本传家宝工具箱)。我不认为多个感叹号比一个感叹号有任何好处。

为什么规范允许这种语法以及它在现实世界的应用程序中有何用处?


在这种情况下,GNU sed 似乎不兼容,如果我们使用多个感叹号,它会抱怨:

$ sed -e '/pattern/!!d' file
sed: -e expression #1, char 11: multiple `!'s

答案1

sed的 API 很原始——这是设计使然。至少,它有留下来原始的设计——我不能说它是否是一开始就被原始设计的。在大多数情况下,编写一个sed脚本,运行时将输出另一个sed脚本确实是一件简单的事情。宏预处理器(例如和/或 )sed经常以这种方式应用。m4make

(接下来是一个高度假设的用例:这是一个为适应解决方案而设计的问题。如果你觉得这有点困难,那么可能是因为它确实如此,但这并不一定会降低它的有效性。)


考虑以下输入文件:

cat <<"" >./infile
camel
cat dog camel
dog cat
switch
upper
lower

如果我们想编写一个sed脚本来附加单词-案件到每个的尾部合适的仅当可以在上面的输入文件中的一行中找到该单词时适当的背景我们希望尽可能高效地完成(这应该是我们的目标,例如在编译操作期间)那么我们应该尽可能避免应用/regexp 。/

我们可以做的一件事是立即在我们的系统上预编辑文件,并且sed在编译期间根本不调用。但是,如果根据本地设置和/或编译时选项应该或不应该包含文件中的任何这些单词,那么这样做可能不是一个理想的选择。

我们可能做的另一件事是处理文件现在反对正则表达式。我们可以生成 - 并将其包含在我们的编译中 - 一个sed可以根据行号进行编辑的脚本 - 从长远来看,这通常是一条更有效的途径。

例如:

n=$(printf '\\\n\t')
grep -En 'camel|upper|lower' <infile |
sed "   1i${n%?}#!/usr/heirloom/bin/posix2001/sed -nf
        s/[^:]*/:&$n&!n;&!b&$n&/;s/://2;\$a${n%?}q"'
        s/ *cat/!/g;s/ *dog/!/g
        s| *\([cul][^ ]*\).*|s/.*/\1-case/p|'

...以脚本的形式写入输出sed,看起来像...

#!/usr/heirloom/bin/posix2001/sed -nf
:1
    1!n;1!b1
    1s/.*/camel-case/p
:2
    2!n;2!b2
    2!!s/.*/camel-case/p
:5
    5!n;5!b5
    5s/.*/upper-case/p
:6
    6!n;6!b6
    6s/.*/lower-case/p
q

当该输出保存到我​​的计算机上名为./bang.sed并运行的可执行文本文件时./bang.sed ./infile,输出为:

camel-case
upper-case
lower-case

现在你可能会问我...我为什么要这么做?为什么我不只是主播grep的比赛?到底谁使用驼峰式大小写?对于每个问题我只能回答,我不知道...因为我不这样做。在阅读这个问题之前,我个人从未注意到多-!解析规范中的要求 - 我认为这是一个非常巧妙的捕获。

多-!事物做过不过,对我来说立即有意义 - 大部分sed规范都是为了简单解析和简单生成的 sed脚本。您可能会发现所需的\newline 分隔符[wr:bt{]在这种情况下更有意义,如果您牢记这个想法,您可能会更好地理解规范的其他一些方面 -(例如:不接受任何地址,并且q拒绝接受超过1个)

在上面的例子中我写出了某种形式sed脚本,它只能曾经读一次。如果您仔细观察,您可能会注意到,在sed读取编辑文件时,它会从一个命令块前进到下一个命令块 - 它永远不会分支或完成其编辑脚本,直到完全完成其编辑文件。

我认为多-!地址在这种情况下可能比在其他一些情况下更有用,但是,老实说,我想不出任何一个案例可以很好地利用它 - 而且我sed很多。我还认为值得注意的是,GNU/BSDsed都未能按照指定的方式处理它 - 这可能不是规范中需求很大的一个方面,因此,如果实现忽略了它,我会非常严重地怀疑它们的虫子@盒子将因此遭受严重损失。

也就是说,未能按规定处理此问题任何假装合规的实现都会出现错误,因此我认为这里需要向相关开发人员发送电子邮件,如果您不这样做,我打算这样做。

相关内容