我的文件内容filename
如下(例如):
My block of line starts from here
START
First line
second line
third line
END
and end to here for example.
我想用一个单词替换START
和之间的行块,例如用。如下所示:END
SINGLEWORD
My block of line starts from here
SINGLEWORD
and end to here for example.
我可以使用以下命令找到我的行块:
grep -Pzo "START(.|\n)*END" filename
上述命令的运行结果如下:
START
First line
second line
third line
END
然后我使用此命令将所有行合并为一行:
LAST_RESULT | sed -e :a -e '/$/N; s/\n/ /; ta'
然后我会得到这个结果:
START First line second line third line END
使用我的最后一个命令,LAST_RESULTS | sed 's/.*/SINGLEWORD/'
我将它们更改为"SINGLEWORD"
并得到了这个结果。
SINGLEWORD
现在我想要的是:如何使用此命令(或您的建议命令)并将我的行块替换为“SINGLEWORD”单词?最终结果将类似于此文件:
My block of line starts from here
SINGLEWORD
and end to here for example.
答案1
这可以很容易地完成perl
:
$ perl -i -p0e 's/START.*?END/SINGLEWORD/s' file
$ cat file
My block of line starts from here
SINGLEWORD
and end to here for example.
解释
-0
将行分隔符设置为空
-p
将给出的脚本应用-e
到每一行并打印该行
正则表达式修饰符:
/s
将字符串视为单行。也就是说,将其更改.
为匹配任何字符,甚至是换行符,而换行符通常不会匹配。
为什么?
:
- 默认情况下,量化子模式是“贪婪的”,也就是说,它会匹配尽可能多的次数(给定一个特定的起始位置),同时仍允许其余模式匹配。如果您希望它匹配的次数尽可能少,请在量词后加上
?
。
答案2
我想知道如果没有和其他方法perl
,这是否可行python
。我使用以下方法找到了解决方案sed
:
$ sed ':a;N;$!ba;s/START.*END/SINGLEWORD/g' filename
解释:
- :A 创建标签“a”
- 否 将下一行附加到模式空间
- $! 如果不是最后一行,巴 分支(转至)标签 'a'
- s 代替,
/START.*END/
经过SINGLEWORD
,/G 全局匹配(尽可能多次)
它被找到了这里。
答案3
尽管ripgrep
不支持内联替换,我发现它的当前--replace
功能对于这种用例已经很有用:
rg --replace 'SINGLEWORD' --passthru --no-line-number \
--multiline --multiline-dotall 'START.*?END' input.txt > output.txt
解释:
--replace 'SINGLEWORD'
启用替换模式并设置替换字符串。可以使用$1
等包含捕获的正则表达式组。--passthru
是必需的,因为ripgrep
通常只显示与正则表达式模式匹配的行。使用此选项,它还会显示文件中所有不匹配的行。--no-line-number / -N
是因为默认情况下ripgrep
在输出中包含行号(当仅显示匹配的行时很有用)。--multiline / -U
启用多行处理,因为它默认是禁用的。--multiline-dotall
仅当您想让点('.')正则表达式模式匹配换行符(\n
)时才需要。> output.txt
是必需的,因为不支持内联替换。使用--passthrough
和no-line-number
选项,标准输出会将所需的新文件与替换文件匹配,并且可以照常保存。
但是,此命令对于处理多个文件不太有用,因为它需要针对每个文件单独运行。