Phil R Lawrence on Wed, 20 Aug 2003 11:42:52 -0400 |
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**
|
|