Category: | Text processing |
Author/Contact Info | Lev Koszegi (lkoszegi<at>standard.com) |
Description: | With much help from answers provided by fellow monks to my previous questions, I have come up with a script (my first real script, actually!) that will read a list of filenames and then apply a series of edits to the files. In the process, it will back the originals up in a tarball. If any of you are willing to look over my code, I'd appreciate feedback. Any lines stand out as the wrong way to do things? Are there things that could be written more elegantly? Can error handling be improved? I'm quite new at Perl, so I wouldn't be surprised if there are things I could have done better. So here's the script, which I've called fled for 'file list edit'. The reason I'm not simply using perl -pi.bak -e 's|foo|bar|g' files is that these files are not necessarily all in the same directory, and besides, the in-place edit feature of Perl changes the owner of the edited file to whoever runs it. This script will maintain the same owners on the original files. Since it runs from a list of files, that list can be generated by grep, or tcgrep, or however. Anyway, here it is: |
#!/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 strict; use File::Copy; use File::Basename; use Cwd; usage() unless $#ARGV == 1; #Require two arguments (list file & patter +n 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 = <FILE_LIST>); #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 = <PATFILE>); 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 "<PATFILE>: 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 read +ing: $!"; open(UPDATED, ">$filename") or die "Cannot open ${filename} for writ +ing: $!"; while (<FILE2CHANGE>) { #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 <<EOF usage: fled [list file] [pattern file] List file is a file containing the list of files to process, one file name per line. Pattern file must contain the substitution expressions, one per line, using forward slashes as delimiters, but omitting the 's' at the beginning (e.g. "/foo/bar/g"). Each line may optionally end with 'g' and/or 'i' switch(es). EOF } |
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Edit a List of Files
by GrandFather (Saint) on Apr 10, 2006 at 20:54 UTC | |
by lev36 (Sexton) on Apr 11, 2006 at 20:54 UTC | |
by GrandFather (Saint) on Apr 11, 2006 at 21:03 UTC | |
Re: Edit a List of Files
by chanio (Priest) on Apr 11, 2006 at 04:03 UTC | |
by lev36 (Sexton) on Apr 11, 2006 at 21:08 UTC |