global search and replace

pll at lanminds.com pll at lanminds.com
Tue May 13 12:17:04 EDT 2003


In a message dated: Tue, 13 May 2003 11:01:20 EDT
bscott at ntisys.com said:

>On Tue, 13 May 2003, at 10:21am, pll at lanminds.com wrote:
>> Well, assuming that all the files are under a single hierarchy, you 
>> could do something like this:
>> 
>>     for i in `find ./ -type f -print | xargs grep foo | cut -f1 -d: | sort -
>u `
>>     do
>>        perl -i.bak -anpe '$_ =~ s/foo/bar/g' $i
>>     done
>
>  Wow, that's... weird.

I was in a rush, I was in a con-call while typing this, and, 
unfortunately, I couldn't think straight while listening to someone 
with a Belgian accent ramble on and on and on :)

>  grep'ing each file for the string to replace just slows things down.  You
>end up grovelling every file at least once, and every matching gets done
>file twice.  Just let Perl do the search.
>
>  The entire 'for' loop is unneeded, and results in Perl getting invoked
>repeatedly; far better to just use xargs to invoke Perl once.

I agree, I just couldn't think in Perl at the moment.

>  Your example breaks on "unsafe" file names.

I have no 'unsafe' file names.  If anyone invoking my solutions does, 
then it's left as an excercise to them to adjust the solutions 
accordingly.

>  The '-p' switch and the '-n' switch conflict in their semantics.  The Perl
>documentation says '-p' overrides '-n', but that's not something I would
>like to depend on.

Sorry, that was a typo.

>  I cannot figure out why you would want to use the '-a' switch at all.

Force of habit.  Almost all my one-liners require a loop which also 
needs autosplit-mode.  Sometimes it's rather difficult to get my 
brain and my fingers to agree on things :)

>  The '=~' binding operator is unnecessary; 's///' operates on the default
>pattern space... well, by default.  :-)

For some reason, I couldn't get things to work correctly without the 
'=~'.  I don't know why, and I didn't spend time debugging it, since 
I was on the con-call.  My solution worked for my very narrow test 
case, and ultimately, that's all most people care about in the end.

Were I to actually have to come up with a solution which would work 
repeatedly on thousands of files, my response would likely have been 
in the form of a script like Kevin's 'transmogrify', which he has 
since posted :)

>  This, IMNSHO, is much better:
>
>  find -type f -print0 | xargs -0 perl -i.bak -pe 's/foo/bar/g'

Ayup, it sure is.  But I didn't think of that solution at the time :)

>  The only thing the above does not do that Paul's example did is sort the
>filenames prior to running the search-and-replace operation.  But, since the
>entire thing is intended to be non-interactive, I'm not really sure what the
>benefit of that sort is.  :-)

I was using 'sort -u' which would output only one instance of the 
file name where a match was found.  I really should have used 'uniq' 
not sort, but again, this is a case where my fingers typed what they 
knew.  I often sort my output *and* require unique lines, so I use 
'sort -u' rather than 'sort | uniq'.

Oh, and the other thing I should have mentioned, IMO, it's best to 
have a huge hierarchy like this under revision control 
(RCS,CVS,Subversion, etc.) so that when you fubar things, it's 
trivial to recover by just reverting to the last good check-in :)
-- 

Seeya,
Paul
--
Key fingerprint = 1660 FECC 5D21 D286 F853  E808 BB07 9239 53F1 28EE

	It may look like I'm just sitting here doing nothing,
   but I'm really actively waiting for all my problems to go away.

	 If you're not having fun, you're not doing it right!





More information about the gnhlug-discuss mailing list