Edit a List of Files
lev36
created: 2006-04-10 16:15:00

#!/usr/bin/perl -w
# Script to make text replacements to a list of files
#
# The author of this script makes no warranty,
# express or implied, that this script will
# do anything useful at all, and any use
# of it is entirely at your own risk.
#
# by Lev Koszegi 4/10/2006

use File::Copy;
use File::Basename;
use Cwd;

usage() unless $#ARGV == 1; #Require two arguments (list file & pattern file)

my (@files, @patterns);
my ($pattern, $filename);
my $now = time;
my $dir = cwd;

open FILE_LIST, $ARGV[0]
  or die "Cannot open file list: $!";
chomp(@files = );
#Test the lines of FILE_LIST to make sure files exist;
#if not, note which one is bad and die.
foreach $filename (@files) {
  die "Invalid file name ($filename): $!" unless -e $filename;
}
close FILE_LIST;

open PATFILE, $ARGV[1]
  or die "Cannot open pattern file: $!";
#Test the pattern file to make sure it looks okay, or die.
chomp(@patterns = );
foreach $pattern (@patterns) {
  #Pattern must begin with a forward slash, contain exactly three
  #unescaped forward slashes, and end with same plus optional g and/or i.
  unless ($pattern =~ /^\/.*[^\\]\/.*[^\\]\/(g|i|gi|ig)?$/) {
    die ": bad pattern: $@";
  }
  #Create the substitution commands.
  $pattern = 's' . $pattern;
}
close PATFILE;

#Create backup directory, timestamped to make it unique.
my $bakdir = "bak_${now}";
mkdir $bakdir, 0755 or die "Cannot create archive directory: $!";

my $tarFile = $bakdir . '/' . "bak.tar";
my $logfile = $bakdir . '/' . "logfile";

#Create log file
open LOG, "> $logfile"
  or die "Cannot create logfile: $!";

select LOG;
$| = 1; # Don't keep LOG entries sitting in the buffer.
select STDOUT;

#Tarball the files to archive current state
!(system "tar", "chvlf", $tarFile, "-I", $ARGV[0]) 
  or die "Cannot create backup archive!";
print LOG "Created archive OK.\n";

!(system "gzip", $tarFile)
  or print LOG "Cannot compress archive; proceeding anyway.\n";

#Loop through each file and make the edit(s)
foreach $filename (@files) {
  #Copy contents of file to a temporary work file.
  my $wkfile = $bakdir . '/' . basename $filename;
  copy($filename, $wkfile) or die "Cannot copy ${filename}: $!";
  open(FILE2CHANGE, "<$wkfile") or die "Cannot open ${wkfile} for reading: $!";
  open(UPDATED, ">$filename") or die "Cannot open ${filename} for writing: $!";
  while () {
  #Run each substitution on the line.
  foreach $pattern (@patterns) {
    eval $pattern;
  }
  print UPDATED;
  }
  print LOG "Processed ${filename}\n";
  close FILE2CHANGE;
  close UPDATED;
  unlink $wkfile;
}

close LOG;

###################################

sub usage {
die <






Re: Edit a List of Files
created: 2006-04-10 16:54:18

A mixture of, mostly minor, stylistic issues:

use strict;
use warnings;

That mantra should come before you do anything else! Always! Regardless of projet size! No exceptions! Comprende?

(condition) or print "fail string";

is cute, but

print "fail string" if condition; 

is clearer. In cases where the fail condition is non-zero it is even better to make it explicit:

print "fail string" if 0 != (condition);

It is tempting to comment things that you have just learned, but that can lead to over commenting and make it harder to grok the flow of the code.

$var1 . 'string1' . "string2" is better written as "${var1}string1string2". Note the ${var1} usage to clarify where the variable name ends.

The block for while () { is not indented.


DWIM is Perl's answer to Gödel
Re^2: Edit a List of Files
created: 2006-04-11 16:54:58

Thanks!

I added use strict;, and fixed the indent problem. As for use warnings;, doesn't the "-w" in #!/usr/bin/perl -w do the same thing?

I don't have time right now, but I'll review the script and consider your other suggestions as well. I do appreciate it!

Re^3: Edit a List of Files
created: 2006-04-11 17:03:36

Yes, -w does do that. I tend not to notice it because on Windows I don't need (and therefore don't supply) the shebang line.


DWIM is Perl's answer to Gödel
Re: Edit a List of Files
created: 2006-04-11 00:03:38
Thank you!

A very useful script.

I would like to add something to my own version of this script:

  • > Log files should speak clear and simple. Those are tools to work with even if the user ignores what the script is doing. After some time, I might forget what was the script doing. When preparing logs for large number of processed files it is easier to read one or two lines clearly identified with each file.
  • > Making a more expressive table of regexes that could load inside a hash with different extensions and another generic key that would apply to all files. That would be easy by just starting from a standard template with fields to fill in. (A kind of ini file where lines starting with # wouldn't count as values. And keys would start without any tab character)
  • > Modules could make this script useful for any platform!
Then this script could become a very powerful tool!

Re^2: Edit a List of Files
created: 2006-04-11 17:08:13

Thanks for your comments, Chanio. I'm considering how to make the log file a little more clear and informative.

Your other suggestions sound good too, though they are more than I have time to figure out right now.

And you should certainly feel free to take it and modify it for your own use! Especially if you share what you did and why, so I can learn yet more.

perlmonks.org content © perlmonks.org and chanio, GrandFather, lev36

prlmnks.org © 2006 edmund von der burg (eccles & toad)

v 0.03