更新 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