Alwanza Home Alwanza Bells and Whistles

#!/usr/bin/perl

# textSubstitute.pl, textSub.pl textSu.pl
# by Meryll Larkin      return to Alwanza
# created 5/11/00    last revision: 8/22/00
# suggestions for improvement encouraged (I'm new at this)

# This perl script will:
# Substitute multiple instances of one string for another
# in files within a directory or nested directories
# provided the string does not extend beyond a single line
# It will ask for the path to the directory
# It will prompt user for error checks in multiple places
# It will allow for original text to contain regular expressions or not
# by user choice
# Make a status report for each directory &
# send the report to screen, file, or both, by user choice.

# to change revision date try regular expression, something like:
# rev\s\d+\s\w+\s\d+ this will match: rev 4 April 2000

# ********************************************************

use Cwd;
$name = ucfirst($ENV{LOGNAME});
print "\nHello $name,\n\n";
print "This script will substitute multiple instances of one string for another\n";
print "in files within a directory or nested directories.\n";
print " * provided the string does not extend over more than one line *\n";
print "You will be asked to provide:\n";
print "   the path to the directory you wish to change\n";
print "   the original text string(s) you wish to change\n";
print "   and the new text string(s) you wish to substitute in place\n";
print "   of the original text\n";
print "You will also be informed of subdirectories found nested within\n";
print "your directory, and asked if you want to make the same changes to the\n";
print "files within those directories.\n\n";

print "Do you wish to continue? (y or n)\n";
&query_continue;
&get_dirpath;
&move_into_dirpath;
&open_Dir;

&get_string_to_replace;

print "\nIn directory $dir, you are about to change the following original text:\n\n";
for ($ia = 0; $ia < $end; $ia++) {
   print "$orgText[$ia] to this: $fixedText[$ia]\n";
}

print "\nDo you wish to continue? (y or n)\n";
&query_continue;
&where_report;

$subdirectToDo[0] = $dir;
chmod(0775, $dir) or die "Can't modify permissions on directory $dir: $!\n";

while ( $subdirectToDo[0] ) {

   &move_into_dirpath;
   &open_Dir;

   if (( $statusloc eq "F") || ( $statusloc eq "B")) {
      # detect & correct for existing status report
      $statfile2 = "StatusReport_old.txt";
      $statfile = "StatusReport.txt";
      if ( -e $statfile ) {
         `cp $statfile $statfile2`;
         # delete statfile so new one will contain only new data.
         unlink ($statfile);
      }
   }

   # find all directory contents OTHER than those that begin and end in .
   @dirContents = grep !/^\.\.?$/, readdir(CHANGEME);

   # separate the files from the subdirectories
   foreach $dirContent ( @dirContents ) {
      #do not include StatusReports in file array for string detection
      if ( $dirContent =~ /tatusRepor/) {
      }
      elsif (-s $dirContent) {
         if (-d $dirContent) {
            $subdirectFound[$#subdirectFound + 1] = $dirContent;
         }
         else {
            $file[$#file + 1] = $dirContent;
         }
      }
      else {
         print "-s (nonzero size) test failed $dirContent\n";
      }
   }

   if (( $statusloc eq "B") || ( $statusloc eq "F")) {
      open ( STATFILE, ">>StatusReport.txt" ) or die "Can't open StatusReport.txt\n";
      if ( !@file ) {
         print STATFILE "No files were detected inside directory $dir\n";
      }
      else {
         print STATFILE "The results for directory $dir:\n";
      }
   }
   if (( $statusloc eq "B") || ( $statusloc eq "M")) {
      if ( !@file ) {
         print "No files were detected inside directory $dir\n";
      }
      else {
         print "The results for directory $dir:\n";
      }
   }

    foreach $file ( @file ) {
       chmod(0775, $file) or die "Can't modify permissions on file $file: $!\n";
       open(INPUT, $file) or die "Can't open $file\n";
       $i = 0;

      for ( $ib = 0; $ib < $end; $ib++ ) {
          $boo[$ib] = "undetected";
       }

      while (<INPUT>) {
          $html[$i] = $_;    #make a line by line array of the file contents
          chomp($html[$i]);
          $html[$i] =~ s/\//;    # delete DOS carriage return characters
          $html[$i] =~ s/\r//;    # delete DOS carriage return characters
          for ( $ib = 0; $ib < $end; $ib++ ) {
             if ( $_ =~ /$orgText[$ib]/ ) {     # detect original string
                $sub = $html[$i];
                # substitute new string for original string
                # did user indicate that string contains regular expression?
                if (( $regex[$ib] ne "Y" ) && ( $regex[$ib] ne "y")) {
                   # the \Q and \E make this a string match and ignore regular expressions
                   $sub =~ s/\Q$orgText[$ib]\E/$fixedText[$ib]/;
                }
                else {    #the default is to honor regular expressions
                   $sub =~ s/$orgText[$ib]/$fixedText[$ib]/;
                }
                $html[$i] = $sub;
                $boo[$ib] = "found";
                if (( $statusloc eq "B") || ( $statusloc eq "F")) {
                   print STATFILE "$orgText[$ib] has been detected in $file.\n";
                }
                if (( $statusloc eq "B") || ( $statusloc eq "M")) {
                   print "$orgText[$ib] has been detected in $file.\n";
                }
             }
          }
          $i++;
       }
       $k = $i;
       for ( $ic = 0; $ic < $end; $ic++ ) {
          if ( $boo[$ic] !~ "found" ) {
             if (( $statusloc eq "B") || ( $statusloc eq "F")) {
                print STATFILE "Unable to find $orgText[$ic] to change inside $file.\n";
             }
             if (( $statusloc eq "B") || ( $statusloc eq "M")) {
                print "Unable to find $orgText[$ic] to change inside $file.\n";
             }
          }
       }
       #make temporary file to hold corrected data
       #deconstruct file name into name and extension
       if ($file =~ /\w\.\w/) {
          $start = index($file, ".");
          $filename = substr($file, 0, $start);
          $extension = substr($file, $start);
       }
       # make temporary file to hold corrected data
       $newfile = "$filename" . "_old" . "$extension";
       # test to make sure file doesn't already exist
       if ( -e $newfile ) {
          $newfile = "$filename" . "_old1" . "$extension";
       }
       if ( -e $newfile ) {
          print "Can't copy $file to $newfile because $newfile already exists.\n";
          print "Quitting.\n";
          exit (0);
       }
       open ( NEWFILE, ">>$newfile" ) or die "Can't open NEWFILE/$newfile\n";
       chmod(0775, $newfile) or die "Can't modify permissions on new file $newfile: $!\n";
       for ( $m = 0; $m < $k; $m++ ) {
          print NEWFILE "$html[$m]\n";
       }
       close ( NEWFILE );    # close files before copying them!!!!!
       close ( INPUT );    # close files before copying them!!!!!
       #put corrected text into original filename
       `cp $newfile $file`;
       # delete temporary file
       unlink ( $newfile );
    }
    shift @subdirectToDo;
    # empty file array so that it will be repopulated with only files in next directory
    $mend = $#file + 1;
    for ( $n = 0; $n < $mend; $n++ ) {
       shift @file;
    }
    if ( @subdirectFound ) {
       if (( $statusloc eq "B") || ( $statusloc eq "F")) {
          print STATFILE "\nSubdirectories were detected inside $dir:\n";
       }
       if (( $statusloc eq "B") || ( $statusloc eq "M")) {
          print "\nSubdirectories were detected inside $dir:\n";
       }

       foreach $subdirectFound ( @subdirectFound ) {
          if (( $statusloc eq "B") || ( $statusloc eq "F")) {
             print STATFILE " $subdirectFound\n";
          }
          if (( $statusloc eq "B") || ( $statusloc eq "M")) {
             print " $subdirectFound\n";
          }
       }
       print "Would you like to make exactly the same changes in any of the subdirectories? (y or n)\n";
       &query_moredir;
       $nend = $#subdirectFound + 1;
       # empty subdirfound array so that it will be repopulated with only child directories
       for ( $n = 0; $n < $nend; $n++ ) {
          shift @subdirectFound;
       }
    }
    else {
       if (( $statusloc eq "B") || ( $statusloc eq "F")) {
          print STATFILE "No subdirectories were detected in $dir.\n\n";
       }
       if (( $statusloc eq "B") || ( $statusloc eq "M")) {
          print "No subdirectories were detected in $dir.\n\n";
       }
    }
    if (( $statusloc eq "B") || ( $statusloc eq "F")) {
       close ( STATFILE );
   }
    # compile an array of completed directories for navigation purposes in subroutine
    unshift (@subdirectDone, $dir);
    &select_nextdir;
}
print "Job completed. Quitting.\n";
closedir ( CHANGEME );
exit (0);

#********************************************************

sub query_continue {
    $continue = substr(<STDIN>, 0, 1);    #take first character only
    $continue =~ tr/a-z/A-Z/;    #transform to upper case
    if (( $continue ne "Y" ) && ( $continue ne "N" )) {
       print "$continue is not a valid answer.\n";
       print "Do you wish to continue? (y or n)\n";
       &query_continue;
    }
    if ( $continue ne "Y" ) {
       print "Quitting per user request.\n";
       exit (0);
    }
}

sub get_dirpath {
    print "Write the full path to the directory that needs changes:\n";
    chomp($dir = <STDIN>);    #remove "enter"
    if ( $dir !~ /\w/ ) {
       &get_dirpath;
    }
}

sub move_into_dirpath {
    $dircurrent = cwd();
    unless ( chdir $dir ) {
       print "Can't move into $dir $!\n\n";
       print "Try again, and follow this format:\n    $dircurrent\n\n";
       &get_dirpath;
       &move_into_dirpath;
    }
    $dircurrent = cwd();
    if ( $dircurrent ne $dir ) {
       print "Is this the directory you want?\n    $dircurrent\n";
       $datagood = substr(<STDIN>, 0, 1);    #take first character only
       $datagood =~ tr/a-z/A-Z/;
       if (( $datagood ne "Y") && ( $datagood ne "N")) {
          print "$datagood is not a valid answer.\n";
          print "Do you wish to continue? (y or n)\n";
          &query_continue;
       }
       if ( $datagood ne "Y" ) {
          &get_dirpath;
       }
       else {
          $dir = $dircurrent;
       }
    }
}

sub open_Dir {
    unless (opendir( CHANGEME, $dir )){
       print "Can't open $dir. Do you wish to rewrite? (y or n)\n";
       &query_continue;
       &get_dirpath;
    }
}

sub get_string_to_replace {
    $datagood = "Y";
    for ($is = 0; $is < 100; $is++) {
       print "\nProvide one original string that you wish to change:\n";
       chomp($orgText[$is] = <STDIN>);    #remove "enter"
       print "Does this string contain specialized characters that you wish to\n";
       print "treat as \"regular expressions\"? (y or n, default = n)\n";
       $regex[$is] = substr(<STDIN>, 0, 1);    #take first character only
       print "Provide the corrected text that you wish to substitute for $orgText[$is]:\n";
       chomp($fixedText[$is] = <STDIN>);    #remove "enter"
       print "\nPlease confirm you want to change the following original text:\n\n";
       print "$orgText[$is]    to this:    $fixedText[$is]        in directory:\n";
       print "$dir.\n\n";
       print "Is this substitution correct? (y or n)\n";
       $datagood = substr(<STDIN>, 0, 1);    #take first character only
       $datagood =~ tr/a-z/A-Z/;
       if ( $datagood ne "Y" ) {
          $is = $is - 1;
       }
       else {
          print "\nWould you like to make another text substitution? (y or n)\n";
          $moretext = substr(<STDIN>, 0, 1);    #take first character only
          $moretext =~ tr/a-z/A-Z/;
          if ( $moretext ne "Y" ) {
             $end = $is + 1;
             $is= 100;
          }
       }
    }
}

sub where_report {
    print "\nWould you like to print the status report\n";
    print "to the monitor (m), to a file (f), or both (b) ?\n";
    $statusloc = substr(<STDIN>, 0, 1);    #take first character only
    $statusloc =~ tr/a-z/A-Z/;
    unless (( $statusloc eq "M" ) || ( $statusloc eq "F") || ( $statusloc eq "B")) {
       print "Please select m, f, or b\n";
       &where_report;
    }
}

sub query_moredir {
    $continue = substr(<STDIN>, 0, 1);    #take first character only
    $continue =~ tr/a-z/A-Z/;
    if (( $continue ne "Y" ) && ( $continue ne "N" )) {
       print "$continue is not a valid answer.\n";
       print "Would you like to make the same changes in subdirectories? (y or n)\n";
       &query_moredir;
    }
    if ( $continue ne "N" ) {
       print "Which subdirectories would you like to include?\n";
       print "Write y or n after each:\n";
       foreach $subdirectFound ( @subdirectFound ) {
          print "\n   $subdirectFound   ";
          $include = substr(<STDIN>, 0, 1);    #take first character only
          $include =~ tr/a-z/A-Z/;
          if ( $include eq "Y" ) {
             chmod(0775, $subdirectFound)
                or die "Can't modify permissions on subdirectory $subdirectFound: $!\n";
             if (( $statusloc eq "B") || ( $statusloc eq "F")) {
                print STATFILE "Text will be changed in subdirectory $subdirectFound\n";
             }
             if (( $statusloc eq "B") || ( $statusloc eq "M")) {
                print "Text will be changed in subdirectory $subdirectFound\n";
             }
             unshift @subdirectToDo, $subdirectFound;
          }
       }
    }
}

sub select_nextdir {
    $dir = $subdirectToDo[0];
    if ( $dir ) {
       print "\nThe next subdirectory selected for changes is $subdirectToDo[0]\n";
       print "Shall we proceed?\n";
       $dircurrent = cwd();
       &query_continue;
       $siend = $#subdirectDone + 1;
       unless (opendir(CHANGEME, $dir)){
          for ( $si = 0; $si < $siend; $si++ ) {
             $old_dir = $subdirectDone[$si];
             opendir( OLDDIR, $old_dir );
             chdir $old_dir;
             $dircurrent = cwd();
             if (opendir( CHANGEME, $dir )) {
                $si = $siend;
                closedir ( OLDDIR );
             }
             else {
                closedir ( OLDDIR );
             }
          }
       }
    }
}