Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

In-Place editing system

by Intrepid (Deacon)
on Oct 10, 2000 at 23:13 UTC ( [id://36097]=sourcecode: print w/replies, xml ) Need Help??
Category: Text Processing
Author/Contact Info Soren Andersen (somian -AT- pobox -DOT- com)
Description:

Update made on Fri, 25 Jul 2003 +0000 ...

...mostly for historical interest; if this horrible code has to remain up on PM it might as well be readable (removed the <CITE> tags and so forth).

Generally: Perl with the -i switch (setting $^I) does in-place editing of files.

Specifically:

Passed a set of arguments for the string to match to a regex and the replacement string, this system will find every file in the current working directory which matches the glob argument and replace all instances of the string.

There's some ugliness here: the need to make 2 duplicates of the @ARGV array (@Y and @O) and the need to write a TMP file to disk (major YEEECHHH). So I am offering it as a work-in-progress with the additional acknowledgement that it *must* be merely a reinvent of the same wheel built by many before me, yet I never have found a finished script to do this (particularly on Win32 which does not possess a shell that will preglob the filename argument for you).

The system consists of two parts: one is the perl one-liner (note WinDOS -style shell quoting which will look so wrong to UNI* folk) and the other is a script file on-disk (which is called by the one-liner). It's probably a decidedly odd way to do this and I may later decide that I must have been hallucinating or otherwise mentally disabled when I wrote it :-).

The system keeps a fairly thorough log for you of what was done in the current session. If optionflag -t is set it will reset all the timestamps on completion of the replacements, allowing one to make a directory-wide substitution without modifying the lastmod attribute on the files (might be highly desirable in certain situations ... ethical ones of course). The -d switch currently doesn't work (like I said this a work in progress). (see next para for explanation). When it worked it was for debugging, that is, doing a dry-run.

The Perl -s switch (option flag to perl itself) wouldn't give me the ability to set custom options in this use (with -e set) nor would the module Getopt::Std. One of my reasons for posting this code is to invite help in coming up with an answer as to "why" (particularly in the case of the latter).

First, the one-liner itself (shown with arbitrary example arguments and -t switch set), followed by the script file p-in-p.p (I follow a naming convention of making Perl application -- executable -- scripts with names *.p, library code in files named *.pl).

Also, please save the file p-in-p.p (or whatever you want to name it) to a reasonable location on your HD and then edit the one-liner below so the system can find it there (fully qualified path specification).

perl -"MFile::Dosglob" -e "sub NX{return shift @ARGV;};$P=quotemeta NX;$S=NX;$gb=NX; $opt_t=($t=NX)?$t:undef; push @ARGV,glob(qq{*.$gb}); @O=@Y=@ARGV; for(@O){ $T{$_}=(stat $_)[9]; print qq{\n},$_,q' ',($lt=localtime($T{$_})),qq{\n} ;} if (! $opt_d){for (@O){splice @O,$n++,1,q{\"}. $_ .q{\"};} open(TF,qq{>TMP.~});print TF join qq{\n},@O,$S,$P;close (TF); ($ev=scalar eval qx{TYPE e:\\scr\\p-in-p.p}) or warn $@; if ($opt_t){ for(@Y){ print STDERR qq{\n$_ ! };$r+=utime(time,$T{$_},$_); }; print qq{\n\n Filetimes restored for $r files out of $ev files.\n\n};}}" "i" "I" "txt" -t

The script file:

#!perl
#p-in-p.p

open LOG, ">LOG.~" or die $!;
@ARGV = split /\n/,`TYPE .\\TMP.~`;
print LOG "Patterns: ",qq{\n} x 2, join qq{\n}, @ARGV[$#ARGV,$#ARGV-1]
+,qq{\n};
$P=pop @ARGV;
$S=pop @ARGV;
@ARGV = sort {uc($a) cmp uc($b)} @ARGV;
print LOG "\n" . @ARGV . " Files: ",qq{\n} x 2, join qq{\n},@ARGV, qq{
+\n};
@ARGV = &Dequote(@ARGV);
my $countfiles = $#ARGV + 1;
$^I=q{.PBU};
$S =~ s#\\@#@#g;
while (<>){
    my $former = $_; chomp $former;
    if (s/($P)/$S/g){
        print LOG qq{\n},q{  Now in file: },
            $ARGV , qq{:\n};
        print LOG qq{Replacing: *${1}* in: } .'"' . $former . '"' .qq{
+\n}.
        qq{with: } .'"'. $_ .'"'. qq{\n};
        print;
    }
 print;
};
close (LOG);
system "notepad LOG.~";
sleep 3;
unlink qw{LOG.~ TMP.~};
return $countfiles;

sub Dequote  {

 for (@_)  {
   $_ = substr ($_,1,(length $_) - 2);
 }
 return @_;
}

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://36097]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (6)
As of 2024-03-28 11:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found