更改字符串的已知单词 1 和 3,同时保持未知单词 2 不变

更改字符串的已知单词 1 和 3,同时保持未知单词 2 不变

我有一个文本文件,我正在尝试查找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 fooyfooashatxfoo 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'

相关内容