我有一个文本文件,我正在尝试查找Word1 Word2 Word3
文本文件中的所有实例并将其替换为Word4 Word2 Word5
. Word2 是未知字符串,但其余单词已知。
这是我到目前为止所尝试过的
我有一个字符串(...) foobarfoo (...)
,我想用它替换它(...) hatbarcar (...)
sed -i 's/foo.*foo/hat.*car/g' data.txt
但我得到的结果是
(...) hat.*car (...)
因此,通配符正在查找我想要的单词字符串,但随后我想使用相同的通配符来编写替换旧字符串的字符串。
这可能吗/有人有什么建议吗?
答案1
问题是
sed -i 's/foo\(.*\)foo/hat\1car/g'
做法是,将其改为fooxfoo fooyfoo
ashatxfoo fooycar
即.*
贪心。
您可以使用perl
其非贪婪.*?
运算符来代替。
perl -i -pe 's/foo(.*?)foo/hat$1car/g'
(它还有一个优点是更可移植。它-i
来自许多实现perl
,但在许多实现中不可用sed
(并且当它可用时,并不是所有人都以相同的方式解释))。
使用 GNU sed
,并且$POSIXLY_CORRECT
不在环境中,您可以执行以下操作:
sed -i 's/foo/\n/g;s/\n\([^\n]*\)\n/hat\1car/g;s/\n/foo/g'
也就是说,替换为行中不能出现的foo
字符(行分隔符),以便我们可以使用它来实现非贪婪等价。\n
[^\n]*
如果环境中存在 POSIXLY_CORRECT,[^\n]
则将匹配除 POSIX 之外的任何字符,而\
不是n
除换行符之外的任何字符。你总是可以这样做:
(unset -v POSIXLY_CORRECT; exec sed...)
如果您希望脚本仍然在设置了 POSIXLY_CORRECT 的环境中工作。
答案2
中的替换字符串s/PATTERN/REPLACEMENT/
不是正则表达式。
你将能够捕获与模式的一点相匹配的内容,如果您愿意,可以在替换中使用它:
sed -r 's/foo(.*)foo/hat\1car/g' file
foo
这将捕获同一行上两次出现的任何内容,并将该位插入到hat
和之间car
。上面\1
说“插入第一个括号捕获的任何内容”。
请注意,这.*
是“贪婪”的,因此如果您有foobarfoofoobarfoo
,\1
则将是barfoofoobar
,而不是bar
。
答案3
使用 sed,您可以使用\(
和\)
来创建一个捕获组,可以\1
在替换的替换部分中引用该捕获组:
sed 's/foo\(.*\)foo/hat\1car/g'