Reputation: 1854
I need to do a find/replace in multiple files but I want to keep the first occurrence of the match and replace all others. THis may have been answered else where but it's a bit difficult to search for.
I am currently using: perl -pi -w -e 's/THING/SOMETHING_ELSE/g;' ./src/**/*.py
A practical example:
from stuff import THING
print(f"use {THING} here")
print(f"use {THING} there")
print(f"use {THING} everywhere")
Should become:
from stuff import THING
print(f"use {SOMETHING_ELSE} here")
print(f"use {SOMETHING_ELSE} there")
print(f"use {SOMETHING_ELSE} everywhere")
Upvotes: 1
Views: 47
Reputation: 132822
It sounds like you want to skip the from
line, so I'd just skip those. This expression either matches that from
or tries to do the substitution. That is, the substitution is not attempted on any line that starts with 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")
This skips every from
line, so if you wanted to change other from
lines, this isn't going to work.
Notice that I also use the \b
word anchor boundaries around THING
. Otherwise, you get what I got I ran the program again: SOMESOMETHING_ELSE_ELSE
:)
There are various other ways to accomplish this task but they aren't so nice as one-liners.
Upvotes: 0
Reputation: 93676
You'll have to check for /THING/
before doing the s/THING/.../
.
Here's how would be as a script thing-to-other
that you can then call as thing-to-other ./src/**/*.py
#!/bin/env perl -i -p
if ( /THING/ ) {
if ( $seen{$ARGV}++ ) {
s/THING/SOMETHING_ELSE/g;
}
}
Note that I got rid of the -w
because the use of the %seen
hash will throw a warning. The %seen
hash keeps track how many times in each input file ($ARGV
) you've seen /MATCH/
.
If you really need it to be a one-liner:
perl -i -p -e'if (/THING/) {if($seen{$ARGV}++){s/THING/SOMETHING_ELSE/g}}'
Upvotes: 1