用 perl 替换多个文件中除第一个匹配项之外的所有匹配项

Replace all matches EXCEPT first match in multiple files with perl

我需要在多个文件中执行 find/replace,但我想保留第一次出现的匹配项并替换所有其他匹配项。这可能已在其他地方得到解答,但搜索起来有点困难。

我目前正在使用:perl -pi -w -e 's/THING/SOMETHING_ELSE/g;' ./src/**/*.py

一个实际例子:

from stuff import THING

print(f"use {THING} here")
print(f"use {THING} there")
print(f"use {THING} everywhere")

应该变成:

from stuff import THING

print(f"use {SOMETHING_ELSE} here")
print(f"use {SOMETHING_ELSE} there")
print(f"use {SOMETHING_ELSE} everywhere")

您必须在执行 s/THING/.../ 之前检查 /THING/

这是一个脚本 thing-to-other,然后您可以将其调用为 thing-to-other ./src/**/*.py

#!/bin/env perl -i -p

if ( /THING/ ) {
    if ( $seen{$ARGV}++ ) {
        s/THING/SOMETHING_ELSE/g;
    }
}

请注意,我去掉了 -w,因为使用 %seen 散列会引发警告。 %seen 哈希会跟踪您在每个输入文件 ($ARGV) 中看到的次数 /MATCH/.

如果你真的需要它成为单线:

perl -i -p -e'if (/THING/) {if($seen{$ARGV}++){s/THING/SOMETHING_ELSE/g}}'

听起来你想跳过 from 行,所以我就跳过那些。此表达式匹配 from 或尝试进行替换。也就是说,不会在以 from:

开头的任何行上尝试替换
$ perl -pi -w -e 'm/^from\s/ or s/\bTHING\b/SOMETHING_ELSE/g;' test.py
from stuff import THING

print(f"use {SOMETHING_ELSE} here")
print(f"use {SOMETHING_ELSE} there")
print(f"use {SOMETHING_ELSE} everywhere")

这将跳过每个 from 行,因此如果您想更改其他 from 行,这将不起作用。

请注意,我还在 THING 周围使用了 \b 单词锚点边界。否则,你得到我得到的我再次运行程序:SOMESOMETHING_ELSE_ELSE :)

有多种其他方法可以完成此任务,但它们不如单行代码好。