我必须从这里开始:
text match$something_here and match$xxx blablabla
text match$something_else_here and match$xxx blablabla
...
对此:
text match$something_here and match$something_here blablabla
text match$something_else_here and match$something_else_here blablabla
...
因此,对于文件中的每一行,我需要更改xxx
第二次出现后的内容match$
以及第一次出现后的内容match$
。
答案1
:%s/match\$\zs\(\w\+\)\(.*match\$\)xxx/\1\2\1/
解释
match\$\zs
:将比赛锚定在第一个match$
;我通常\zs
在那之后开始比赛,以避免另一个捕获组\(\w\+\)
:捕获第一次出现后的文本match$
\(.*match\$\)
:捕获之后的内容,直到第二次出现match$
,并捕获我们想要保留的内容xxx
:匹配被替换的内容
替代品:第一次出现后的文本,然后是中间的文本,然后是第一个文本(替换xxx
)。
答案2
尝试这个:
sed -e 's/\(match\$\)\([a-zA-Z_]\+\)\([a-zA-Z ]\+match\$\)[a-zA-Z]\+/\1\2\3\2/' < input.txt > output.txt
使用input.txt
以下的一个:
text match$something_here and match$xxx blablabla
text match$something_else_here and match$xxx blablabla
我得到一个output.txt
:
text match$something_here and match$something_here blablabla
text match$something_else_here and match$something_else_here blablabla
答案3
:%s/\v(match\$(\w+).*match\$)xxx/\1\2/
- \v 非常神奇(我们可以少用\\)
答案4
sed -e 's/\(match\)\([_[:alnum:]]*\)\(\(.*\)\n\)*/\1\
/2;tc' -e b -e :c -e 's//\1\2\4\2/'
上面的序列将始终只处理match
一行中第一次和第二次出现的 ,无论一行中可能有多少个。
s///
它的工作原理是在模式的 cd 出现处进行第一次替换s///2
,然后,如果替换t
成功,b
则转移到:c
继续标签,或者如果不成功,则b
转移出脚本。
因此,当该模式出现第二次匹配时,将针对 2cds///
替换命令重复该模式。但如果没有,这些行就会照常打印。
重要的是\(\(.*\)\n\)*
子表达式。该子表达式仅与第一个命令的空字符串匹配,s///2
因为\n
ewline 只能sed
作为编辑的结果出现在模式空间中。但是,当重复该模式时,会\(\(.*\)\n\)*
匹配两个match
es 之间出现的任何/所有字符,因为先前的替换在替换 时s///
插入了ewline 。因此,相同的重复模式可能意味着两种不同的事物,具体取决于其在脚本中的上下文。\n
[_[:alnum:]]*
虽然上面的版本应该按照为任何 POSIX 编写的方式工作sed
(强调应该- 许多sed
s 不符合重复子表达式标准),使用 GNUsed
你可以把它写得短一点:
sed -E 's/(match)(\w*)((.*)\n)*/\1\n/2;T;s//\1\2\4\2/
' <<\IN
text match_something_here and !m!atch_xxx blablabla
text match_something_here and match_xxx blablabla
text match_something_else_here and match_xxx blablabla
text match_something_here and match_xxx blablabla match_xxx blablabla
text match_something_else_here and match_xxx blablabla match_xxx blablabla match_xxx blablabla
IN
...<<\IN
通过IN
位只是此处文档的输入,因此我可以演示它是如何工作的 - 您可能应该<input_file
在其位置使用。另请注意,我将您的$something
和更改$xxx
为_something
和 ,_xxx
因为我的理解是,这些美元符号实际上不应包含在替换模式中,而应替换为其他内容。如果为 true,那么您可以将\w*
ord 转义保留在那里,或者,如果您确实希望包含文字美元符号,那么您仍然应该定义自己的字符类并将其添加为:[$_[:alnum:]]*
。
请注意,tc' -e b -e :c -e
在 GNU 中sed
, 被缩短为只是一个T
.然而,可移植的t
est 导致了成功的替换,b
超过了不成功的行的范围b
,而使用 GNU,sed
您可以T
est 获得不成功的结果 - 它直接将它们分支出来,并且在该点仍然执行脚本的唯一行是那些做过成功地用第二个匹配对替换了一条\n
线。
任何状况之下,(取决于sed
)以上任一将打印:
text match_something_here and !m!atch_xxx blablabla
text match_something_here and match_something_here blablabla
text match_something_else_here and match_something_else_here blablabla
text match_something_here and match_something_here blablabla match_xxx blablabla
text match_something_else_here and match_something_else_here blablabla match_xxx blablabla match_xxx blablabla