|
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
OK,
like it hasn't been done before... :-) But I was just dying for a useful global search and replace script while working on something here at work.
Goals:
- everyone at my shop can use it easily
e.g. interactive approval of resulting diff
- I can use it in advanced ways
e.g. piplining, s///e
I did have trouble parameterizing the s/// modifiers. Lookaheads seem only viable for the match expression, not the whole s/// operator. Any clues? This now works well enough for me to continue on with my real project, so I thought I'd throw it out to you guys for some "extreme programming". (i.e. please cloo me in as needed, and share your undoubtedly niftier implementations :-)
prl
#!/usr/bin/perl
use warnings;
use diagnostics;
use strict;
use Getopt::Long;
use File::Temp qw/ tempfile /;
my $i; # analagous to Perl interpreter -i option
my $e; # this number of e's will be tacked onto end of s///
my $ss; # search string
my $rs; # replace string
my $rc; # replace code, used with the -e flag
my $sp; # search pattern
my $v; # verbose
GetOptions (
'i:s' => \$i,
'e:n' => \$e,
'search_string|ss|s=s' => \$ss,
'replace_string|rs|r=s' => \$rs,
'replace_code|rc=s' => \$rc,
'search_pattern|sp=s' => \$sp,
'pager=s' => \$ENV{PAGER},
'verbose!' => \$v,
);
### set variables appropriately ###
# temporary, until I get Term::Interact upgraded to allow
# console interaction without interrupting STDIN/OUT...
my $console = *STDOUT;
$sp = qr/$sp/ if $sp; # does this really save me anything?
$ss = quotemeta $ss if $ss;
die "No replacement string or code specified\n" unless $rs or $rc;
if ($rc) {
$e = 1 unless $e;
}
### main logic ###
my ($orig, $new, $bkp);
my $fh_new;
if (defined $i) {
die "Only one file can be specified if using the -i flag.\n" if $#ARGV;
die "$ARGV[0] is not a valid file\n" unless -s $ARGV[0];
$orig = $ARGV[0];
unless ($i eq '') {
($bkp = $i) =~ s/\*/$orig/g; #just like -i with Perl interpreter
}
($fh_new, $new) = tempfile;
} else {
$fh_new = *STDOUT;
}
# set up regex. can't figure out how to use a variable for substitution
# modifiers in a regular s///, so instead I have to eval this stringy s///.
my $s = defined $sp ? $sp : $ss;
my $r = defined $rc ? $rc : $rs;
my $m = 'og';
$m .= 'e' x $e if defined $e;
print $console "Substitution will be: s/$s/$r/$m\n" if $v;
while (<>) {
eval "s/$s/$r/$m";
print $fh_new $_;
}
close $fh_new;
exit unless defined $i;
print "Press ENTER to view diff of old vs. new ... ";
my $stdin = <STDIN>;
# TODO: use Algo::Diff or something to help poor Win32 folk
my $args = "diff $orig $new"
. (exists $ENV{PAGER} ? (' | ' . $ENV{PAGER}) : ());
system $args and die "system $args failed: $?";
print "Discard or keep changes? [D|k]: ";
chomp ($stdin = <STDIN>);
if ($stdin eq 'k') {
if (defined $bkp) {
rename $orig, $bkp;
print "Backed up original to $bkp\n";
}
rename $new, $orig;
print "Saved new to $orig\n";
} else {
unlink $new;
}
-
**Majordomo list services provided by PANIX <URL:http://www.panix.com>**
**To Unsubscribe, send "unsubscribe phl" to majordomo@lists.pm.org**
|
|