更新 2020 年 5 月 26 日
看来这是一个错误,所以我提交了一个错误。它的 ID 是#41558。
我只是在乱搞sed
,我想出了这个练习:替换倒数第三个出现的“and”(这个词,不是子字符串),以创建:
dog XYZ foo and bar and baz land good
我以为这会起作用
echo 'dog and foo and bar and baz land good' |
sed -E 's/(.*)\band\b((.*\band\b){2})/\1XYZ\2/'
但它实际上取代了倒数第二个出现的“and”。我能想到的唯一解释是它包含“土地”作为其中之一\band\b
,但情况不应该是这样,因为我包含了“\b
边界”一词?
答案1
这很难做到,因为sed
不支持环视等(正如您可以在 PCRE 中所做的那样)。反转字符串并替换从头开始第三次出现的反转单词,然后再次反转会更容易。
$ echo 'dog and foo and bar and baz land good' | rev | sed 's/\<dna\>/XXX/3' | rev
dog XXX foo and bar and baz land good
至于为什么你的表达不起作用,这看起来像是一个错误。反向引用\3
似乎是 string baz land
,就好像\b
before and
in.*\band\b
从未产生过任何效果。
命令
sed -E 's/(.*)\<and\>((.*\<and\>){2})/\1XYZ\2/'
sed
似乎在 OpenBSD 上用它的原生(使用\<
和\>
代替\b
)做了正确的事情。
sed
我还没有找到针对 GNU或 GNU 的现有错误报告glibc
,尽管如果它至少是这样的话我也不会感到惊讶有关的到glibc 错误 25322(因为,见下文)。
您可以通过更详细的方式来解决这个问题:
sed -E 's/(.*)\band\b(.*\band\b.*\band\b)/\1XYZ\2/'
答案2
我建议提出问题。我已经测试了这些示例,这会导致GNU grep
,GNU sed
和产生相同的行为GNU awk
。除了下面提到的一种情况。
错误的输出:
$ echo 'cocoa' | sed -nE '/(\bco){2}/p' cocoa
sed -nE '/(\<co){2}/p'
并且awk '/(\<co){2}/'
也有错误的行为,但grep -E '(\<co){2}'
正确地没有给出输出行为正确,没有输出:
$ echo 'cocoa' | sed -nE '/\bco\bco/p'
it
输出错误:后面只有 1 个完整单词with
$ echo 'it line with it here sit too' | sed -E 's/with(.*\bit\b){2}/XYZ/' it line XYZ too
行为正确,输入未修改
$ echo 'it line with it here sit too' | sed -E 's/with.*\bit\b.*\bit\b/XYZ/' it line with it here sit too
将单词边界更改为
\<
和\>
会导致不同的问题。这正确不修改输入:
$ echo 'it line with it here sit too' | sed -E 's/with(.*\<it\>){2}/XYZ/' it line with it here sit too
这正确修改了输入
$ echo 'it line with it here it too' | sed -E 's/with(.*\<it\>){2}/XYZ/' it line XYZ too
但是这个无法修改输入
$ echo 'it line with it here it too sit' | sed -E 's/with(.*\<it\>){2}/XYZ/' it line with it here it too sit
此外,只有当冲突的单词开头有额外的字符时,才会出现有问题的行为。例如,it
和sit
。但如果末尾有字符则不然。例如,it
和site
。item
$ echo 'it line with it here item too' | sed -E 's/with(.*\bit\b){2}/XYZ/'
it line with it here item too
$ echo 'it line with it here it too item' | sed -E 's/with(.*\<it\>){2}/XYZ/'
it line XYZ too item