1#!/usr/bin/env perl
2#
3# Copyright 2004 Mattias Gaertner
4#
5# Search and replace in multiple files with perl syntax
6
7use vars qw/ %opt /;
8use Getopt::Std;
9my $opt_string = 'hvcsinbRf:r:m:';
10getopts( "$opt_string", \%opt ) or usage();
11usage() if $opt{h};
12
13sub usage(){
14  print STDERR << "EOF";
15
16Replace strings in files with perl search and replace syntax
17
18usage: $0 [-hRvcnbis] -f text -r replacetext -m filemask file1 file2 ...
19
20 -h            : this (help) message
21 -f <text>     : find text
22 -r <text>     : replace with this text
23 -R            : recursive
24 -i            : case insensitive
25 -v            : verbose
26 -c            : print changes
27 -s            : write summary
28 -n            : simulate, do not change files
29 -b            : replace in binary files too
30 -m <filemask> : file mask, useful for recursive
31
32examples:
33  Replace in file1.txt and file2.txt all a with b
34    $0 -vsn -f 'a' -r 'b' file1.txt file2.txt
35
36  Replace in file1.txt all a([0-9]) with b$1
37    $0 -vsn -f 'a([0-9])' -r 'b$1' file1.txt
38
39EOF
40  exit;
41}
42
43usage() unless $opt{f}; # Text needed
44usage() unless $opt{r}; # Replacetext needed
45
46$FindText=$opt{f};
47$ReplaceText=$opt{r};
48$FileMask=$opt{m};
49
50if($opt{v}){
51  print "Parameters:";
52  print "FindText=$FindText\n";
53  print "ReplaceText=$ReplaceText\n";
54  print "FileMask=$FileMask\n";
55  print "\n";
56}
57
58$TotalFiles=0;
59$ChangedFiles=0;
60$TotalLines=0;
61$ChangedLines=0;
62for $Filename(@ARGV){
63  DoFile($Filename,1);
64}
65if($opt{s}){
66  print "\nSummary:\n";
67  print "changed files: $ChangedFiles/$TotalFiles\n";
68  print "changed lines: $ChangedLines/$TotalLines\n";
69}
70
71#==============================================================================
72
73sub DoFile(){
74  (my $Filename,$Level) = @_;
75
76  # skip special files
77  if($Filename eq "."){ return; }
78  if($Filename eq ".."){ return; }
79
80  #print "DoFile $Filename\n";
81
82  #
83  if(-d $Filename){
84    if($opt{R}){
85      if($opt{v}){
86        #print "Entering directory $Filename\n";
87      }
88      $Filenames=`ls -1 $Filename`;
89      for $SubFilename(split("\n",$Filenames)){
90        DoFile($Filename."/".$SubFilename,$Level+1);
91      }
92      if($opt{v}){
93        #print "Leaving directory $Filename\n";
94      }
95    }
96    return;
97  }
98  if ((! $opt{b}) && (-B $Filename)){
99    if($opt{v} && ($Level==1)){
100      print "Skipping binary file $Filename\n";
101    }
102    return;
103  }
104  if(($FileMask) && ($Filename !~ /$FileMask/)){
105    return;
106  }
107
108  my $FilenamePrinted = 0;
109  if($opt{v}){
110    print "Editing $Filename ...\n";
111    $FilenamePrinted = 1;
112  }
113
114  $TotalFiles++;
115  open F, "< $Filename" or die "Unable to read file $Filename: $!";
116  $NewText="";
117  $LineNumber=1;
118  $FileChanged=0;
119  while ($Line=<F>){
120    $TotalLines++;
121    $OldLine=$Line;
122    if($opt{i}){
123      $Line=~s/$FindText/$ReplaceText/goi;
124    } else {
125      $Line=~s/$FindText/$ReplaceText/go;
126    }
127    if($OldLine ne $Line){
128      $ChangedLines++;
129      $FileChanged=1;
130      if($opt{v} || $opt{c}){
131        if (! $FilenamePrinted){
132          print "Editing $Filename ...\n";
133          $FilenamePrinted = 1;
134        }
135        print "($LineNumber,old):".$OldLine;
136        print "($LineNumber,new):".$Line;
137      }
138    }
139    $NewText.=$Line;
140    $LineNumber++;
141  }
142  if($FileChanged==1){
143    $ChangedFiles++;
144  }
145  close F;
146
147  if(! $opt{n}){
148    open F, "> $Filename" or die "Unable to write file $Filename: $!";
149    print F $NewText;
150    close F;
151  }
152}
153
154# end.
155
156