sed 每次只匹配单词边界

sed 每次只匹配单词边界

我想在命令文件中保留替换列表:

subs.sed

s/hello/foo/g
s/world/bar/g

我这样运行sed -i -f subs.sed file.txt

file.txthello world变为foo bar.

不过,我想阻止这种情况发生:如果file.txthelloworld,我不希望发生上述两个替换中的任何一个。目前的输出是,foobar但我希望输出是helloworld

我可以在命令文件中手动指定字边界:

s/\<hello\>/foo/g
s/\<world\>/bar/g

但我更愿意让这个文件尽可能地易于人类阅读,而不是用这种冗长的内容来掩盖它。

是否有一个命令行选项可以使其sed自身仅匹配整个单词?当然,如果有另一种方法来编辑命令行(在运行 sed 之前先在命令文件上运行 sed?但我担心解析复杂的替换),这种方法尽可能万无一失,那就太好了。

这是 Ubuntu 22.04 上的 GNU sed

答案1

首先,如果您正在运行 GNU (sedLinux 系统上的默认设置),您还可以简化您的sed使用\b,而不是\>and\<这可能会让您更容易理解:

$ cat subs.sed 
s/\bhello\b/foo/g
s/\bworld\b/bar/g

也就是说,我认为您无法执行您所描述的操作,但这里有一个解决方法:保持文件原样,但添加预处理步骤:

$ sed -e 's|/|/\\<|' -e 's|/|\\>/|2' subs.sed 
s/\<hello\>/foo/g
s/\<world\>/bar/g

在这里,我们将两个命令传递给sed.第一个将替换第一次出现的/with /\<,第二个将替换第二次/出现的/\>。我们需要\\>and\\<因为\是转义字符,所以我们需要通过添加另一个字符\来将其视为文字反斜杠来转义它。然后,2第二个命令末尾的 表示“在该行的第二个匹配项上执行此操作”。通过示例更容易解释:

$ echo "......" | sed 's/./A/'
A.....
$ echo "......" | sed 's/./A/2'
.A....
$ echo "......" | sed 's/./A/3'
..A...
$ echo "......" | sed 's/./A/4'
...A..

因此,有了该命令,您就可以创建一个小别名来运行实际的替换,只要您使用的 shell 能够理解<()for流程替代:

$ sed -f <(sed -e 's|/|/\\<|' -e 's|/|\\>/|2' subs.sed) file.txt 
foo you
the bar
helloworld

而且,为了让您的生活更轻松一些,您可以将此行添加到 shell 的初始化文件(~/.bashrc例如)中以创建别名:

alias mysub="sed -i -f <(sed -e 's|/|/\\<|' -e 's|/|\\>/|2' /path/to/subs.sed)"

打开一个新终端,您现在可以运行mysub file并获得预期的输出。

相关内容