我想在命令文件中保留替换列表:
subs.sed
s/hello/foo/g
s/world/bar/g
我这样运行sed -i -f subs.sed file.txt
file.txt
从hello world
变为foo bar
.
不过,我想阻止这种情况发生:如果file.txt
是helloworld
,我不希望发生上述两个替换中的任何一个。目前的输出是,foobar
但我希望输出是helloworld
。
我可以在命令文件中手动指定字边界:
s/\<hello\>/foo/g
s/\<world\>/bar/g
但我更愿意让这个文件尽可能地易于人类阅读,而不是用这种冗长的内容来掩盖它。
是否有一个命令行选项可以使其sed
自身仅匹配整个单词?当然,如果有另一种方法来编辑命令行(在运行 sed 之前先在命令文件上运行 sed?但我担心解析复杂的替换),这种方法尽可能万无一失,那就太好了。
这是 Ubuntu 22.04 上的 GNU sed
答案1
首先,如果您正在运行 GNU (sed
Linux 系统上的默认设置),您还可以简化您的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
并获得预期的输出。