假设我的文件如下所示:
foo bar
foo bar bar
foo foo bar foo
我想要做的是删除所有foo
以 a 结尾的字符bar
(即它们之间只有空格),而不更改任何空格。下面,我已将所有应删除的字符替换为下划线,以使其更清晰:
___ bar
___ bar bar
foo ___ bar foo
该命令应生成以下文件:
bar
bar bar
foo bar foo
我如何使用 sed 或 awk 实现这一点?
答案1
好的,我找到了如何做到这一点的方法。使用 sed 执行此操作的命令如下:
sed -i -E 's/foo([[:blank:]]*)bar/\1bar/' file
答案2
对于支持 perl 兼容正则表达式 (PCRE) 的任何内容,您都可以使用正向前瞻:
perl -pe 's/foo(?=\s*bar)//' < txt
(?=)
是“零宽度正向前瞻断言“。
它需要匹配整个 RE 才能匹配,但它不包括它匹配的内容,所以您不需要捕获并重新插入匹配的文本。
此外,还有负向前瞻,以及正向和负向后瞻,统称为“环视”。
答案3
使用拉库(以前称为 Perl_6)
~$ raku -pe 's:g/ foo <?before \s* bar> //;' file
#OR
~$ raku -pe 's:g/ <(foo)> \s* bar //;' file
上述答案是用 Raku 编写的,Raku 是 Perl 系列编程语言的成员之一。Raku 的优势包括内置的高级 Unicode 支持,以及强大/精炼的正则表达式实现。上面,Raku 正则表达式在识别域(的左半部分s///
)中具有空格容忍性,因此正则表达式原子可以展开(并排列)。此外,所有正则表达式修饰符:global
(例如 或:g
)都移至 Raku 中的运算符头部s///
。与 Perl 一样,全局标志或“副词”允许每行有多个匹配项。
第一个答案是 @jcaron 出色的 Perl(5) 答案的粗略翻译。请注意,在 Raku 中,正向前瞻拼写为<?before ... >
。第二个答案使用 Raku 的<(
...)>
捕获标记,因此在所有三个原子匹配后,仅foo
在捕获中保留 (并在替换中删除)。
这两个答案都特别改变了foo
,bar
中间只有空格。这是一个重要的点:给定短语“my valentine, my bloody valentine”,Raku 代码s:g/my <?before \s* valentine> //
将删除第一个“my”(因为“my-之前-valentine),但第二个“my”保持不变。