regex - 当区域重叠时,Sed 不会替换文件中的所有实例

标签 regex linux bash sed

我需要用其他词替换几个词。

例如:文件中的“apple”和“FRUIT”,仅在这 4 种情况下:

  • _apple_,前后各有一个空格。
  • [apple_,前面有一个方括号,后面有一个空格。
  • _apple],前面有一个空格,后面有一个方括号。
  • [apple],前后有方括号。

我不希望在任何其他情况下发生替换。

我试过使用下面的代码:

a="apple"
b="fruit"
sed -i "s/ $a / $b /g" ./file
sed -i "s/\[$a /\[$b /g" ./file
sed -i "s/ $a\]/ $b\]/g" ./file
sed -i "s/\[$a\]/\[$b\]/g" ./file

我认为最后的选项“g”意味着它将替换所有实例,但我发现这不是一个彻底的解决方案。例如如果 file 包含这个:

apple spider apple apple spider tree apple tree

第三次出现的“apple”未被替换。同样在这里面,几个词的出现没有改变:

apple  spider apple apple apple apple apple spider tree apple tree

我怀疑这是因为共享“空间”。

我怎样才能找到 $a 的所有实例并将其替换为 $b,而不考虑任何重叠?

最佳答案

快速而肮脏的解决方案是执行两次替换。

$ echo apple apple apple apple[apple apple] | sed -e 's/\(\[\| \)apple\( \|\]\)/\1FRUIT\2/g; s/\(\[\| \)apple\( \|\]\)/\1FRUIT\2/g'
apple FRUIT FRUIT apple[FRUIT FRUIT]

这是安全的,因为在第一个命令之后,生成的文本将不会包含原始文本中不存在的任何 (\[| )apple( |\])

缺点是两次替换需要大约两倍的时间来运行。

如果你在 sed 的两次执行中打破它,你可以看到更清晰的步骤:

$ echo apple apple apple apple apple apple[apple apple] | sed -e 's/\(\[\| \)apple\( \|\]\)/\1FRUIT\2/g'
apple FRUIT apple FRUIT apple apple[FRUIT apple]

$ echo apple FRUIT apple FRUIT apple apple[FRUIT apple] | sed -e 's/\(\[\| \)apple\( \|\]\)/\1FRUIT\2/g'
apple FRUIT FRUIT FRUIT FRUIT apple[FRUIT FRUIT]

关于regex - 当区域重叠时,Sed 不会替换文件中的所有实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8752268/

相关文章:

linux - 在 while 循环中计数

javascript - 在 jQuery 中使用正则表达式检查模式

用 R 字符串中的反斜杠下划线 "_"替换下划线 "\_"

linux - 在 Oracle 数据库上安排的作业的性能与在 Linux cron 选项卡上安排的相同作业的性能

python - 终端关闭时应用程序关闭,如何停止?

linux - Word 未扩展为 bash 中的 shell 命令

捕捉[框]的JavaScript正则表达式

python - 仅删除特定位置的逗号

android - 如何在 adb shell 上使用 su 命令?

php - 在 cron 作业中执行 PHP 脚本