“ sed”中的范围运算符实际上是做什么的,它在GNU / busybox中被破坏了吗?

时间:2019-03-27 00:49:19

标签: sed posix busybox gnu-sed

我想知道“ sed”的GNU和BusyBox实现是否可能被破坏。

我的默认sed实现是GNU的实现。

POSIX说:

  

带有两个地址的编辑命令应选择包含的内容   从与第一个地址匹配的第一个模式空间开始的范围   通过与第二个匹配的下一个模式空间。

但是为什么给

$ { echo ha; echo ha; echo ha; } | sed '0,/ha/ !d'
ha

代替

ha
ha

?显然,这里的第二个“ ha”是匹配的“下一个”模式空间,因此也应将其输出!

但更奇怪的是,

$ { echo ha; echo ha; echo ha; } | busybox sed '0,/ha/ !d'

根本不输出任何东西!

但是,即使sed会执行POSIX定义所说明的内容,但仍不清楚当实际检查范围表达式时应该发生什么。

每个范围条件是否都有自己的内部状态?还是sed脚本中所有范围条件都只有一个全局状态?

显然,范围条件至少需要记住它当前处于“搜索第一地址的匹配”状态还是处于“搜索第二地址的匹配”状态。也许它甚至需要记住第三个状态“我已经处理了范围,无论如何都不会再匹配”。

更新这些条件当然很重要:每次读取一个新的模式空间?每次修改模式空间时,例如使用s命令?还是只是控制流达到了范围条件?

那是什么?

直到我进一步了解为止,我将避免在sed脚本中使用范围条件,并将其视为可疑功能。

1 个答案:

答案 0 :(得分:3)

两个答案:

  1. 0不是有效的POSIX地址(行数从1开始)
  2. 0,/re/是GNU扩展

GNU awk手册页包括:

  

0,addr2

     

以“匹配的第一个地址”状态开始,直到addr2为     找到了。这类似于1,addr2,不同之处在于如果addr2匹配     输入的第一行0,addr2形式将在末尾     的范围,而1,addr2形式仍将位于     其范围的开始。仅当addr2为常规时才有效     表达。

也许这将有助于阐明:

$ { echo ha1; echo ha2; echo ha3; } | sed '0,/ha/ !d'
ha1

$ { echo ha1; echo ha2; echo ha3; } | sed '1,/ha/ !d'
ha1
ha2

$ { echo ha1; echo ha2; echo ha3; } | sed --posix '0,/ha/ !d'
sed: -e expression #1, char 8: invalid usage of line address 0

busybox代码显式检查addr1大于0,因此从不进入匹配状态。参见the busybox source code, line 1121

            || (sed_cmd->beg_line > 0

  1. 每个匹配项都保持自己的状态,因为多个匹配项可以同时处于活动状态。

POSIX说:

  

具有两个地址的编辑命令应从与第一个地址匹配的第一个模式空间到与第二个地址匹配的下一个模式空间选择包含范围。 (如果第二个地址的数字小于或等于第一个选择的行号,则只能选择一个行。)从所选范围之后的第一行开始,sed应当再次寻找第一个地址。此后,应重复该过程。

每次遇到都会进行测试:

$ { echo ..a; echo ..b; echo ..c; } |\
  sed -n '
             =;
             y/cba/ba:/;
     1 ,/b/  s/$/ 1/p;
    /a/,/c/  s/$/ 2/p;
     2,  3   s/$/ 3/p;
  '
1
..: 1
2
..a 1
..a 1 2
..a 1 2 3
3
..b 1
..b 1 2
..b 1 2 3

例如,the busybox source code也对此进行了演示-请参见sed_cmd_s typedef。