#!/bin/perl # # Script: global-replace.pl # Description: Ask user for key-pairs to replace in multiple files. # # Version: 2.0 # Last Update: 06 February 2002 # Written by: Dusan U. Baljevic dusan.baljevic@ieee.org # # Copyright 2002-2014 Dusan Baljevic # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # # Make the script tight. # $ENV{'PATH'} = '/bin:/usr/bin:/usr/local/sbin'; $ENV{'SHELL'} = '/bin/sh' if $ENV{'SHELL'} ne ''; $ENV{'IFS'} = '' if $ENV{'IFS'} ne ''; $login = getlogin || getpwuid($<); use strict; use POSIX 'uname'; use POSIX qw(locale_h); use Term::ReadKey; use File::Basename; use Getopt::Std; require Mail::Send; use File::Copy; # Abort the execution if not interactive. # if ( !I_am_interactive() ) { exit(1); } use vars qw($Groupname $Groupowner $Username $Setpwuid $answer $DIRN @userinput @Extraarr $Oldstring $Newstring $fh $Oldfile $Newfile $cnt $LINE $Onerecord @Onerecord $RecipientX $opt_d $opt_a $opt_f $Findcomm $Arr $def $Commandname @find $msg $header @values @VALIDARRAY $login $LC_CTYPE $input $Root_check $Oner @Oner $Usage $Defext $Defdir $Extension $Olds $Fullsearch $News @Onemore); setlocale( LC_CTYPE, "en_AU.ISO8859-1" ); # Flag to enforce that root cannot run the script. # $Root_check = 1; # Effective UID # #if ($Root_check && $> == 0) { # # Real UID # #if ($Root_check && $< == 0) { # #if ($Root_check && ($login = "root")) { # print "ERROR: You should not be running this as root!\n"; # exit(1); #} $Defext = "txt"; $Defdir = "/home/users1"; # Directory with files to replace. $Commandname = basename($0); $Usage = "USAGE: $Commandname [-d /dir/path] [-f file-extension]. $Commandname [-d /dir/path] -a OPTIONS -d search_directory (if not defined, default value is $Defdir) -f file_extension (if not defined, default value is $Defext) -a search all files in given directory\n"; getopts("d:f:a") or die "$Usage"; if ($opt_d) { if ( grep( /^\//, $opt_d ) && ( -d "$opt_d" ) ) { $DIRN = "$opt_d"; } else { print "ERROR: Bad directory definition \"$opt_d\".\n"; die "$Usage"; } } else { $DIRN = "$Defdir"; } if ($opt_f) { if ( $opt_f =~ /^([-\@:\w.]+)$/ ) { $Extension = "$opt_f"; } else { print "ERROR: Bad file extension definition \"$opt_f\".\n"; die "$Usage"; } } else { $Extension = "$Defext"; } if ($opt_a) { $Fullsearch = "$opt_a"; $Extension = "No extensions - full directory search!"; } # Owner of files. # $Groupname = "usergrp1"; $Username = "user1"; $Groupowner = getgrnam($Groupname); $Setpwuid = getpwnam($Username); # Who will receive warnings via email? # $RecipientX = "sysadmin"; sub Send_warn() { $msg = new Mail::Send; $msg->to("$RecipientX"); $msg->subject("WARNING: Change permissions on $Oldfile failed!"); $msg->set( $header, @values ); $msg->add( $header, @values ); $msg->delete($header); $fh = $msg->open; print $fh "Pathfind Admins/Operations: Check $Oldfile IMMEDIATELY.\n"; print $fh "File $Oldfile should have:\n"; print $fh "\t\tPermissions: 775\n"; print $fh "\t\tOwnership: $Setpwuid ($Username)\n"; print $fh "\t\tGroupOwnership: $Groupowner ($Groupname)\n"; $fh->close; } # Default mode for script execution. # "n" stands for "do not run". # $def = "n"; undef $answer; print "\nNOTE: Welcome to global parameter replacement in $DIRN.\n"; print "NOTE: Do you want to proceed (Y|N) (default is N)?\n"; # Ask user to confirm or aborth the script execution. # In CBREAK mode, no need to type in key. # Wait three seconds for user input. If nothing comes, # assume "N" and quit. # &Raw_Term_Mode; if ( lc("$answer") eq "$def" ) { print "\nNOTE: Aborting global parameter replacement at your request.\n"; exit(0); } print "\n\nNOTE: Type in space-separated key-pair values, one set per line.\n"; print "NOTE: Valid characters are: a-z A-Z 0-9 _ - : \@ \$ /\n"; print "NOTE: Type in End-Of-File (Unix: CTRL-D) on a separate line when finished.\n"; print "EXAMPLE: newlove_2 newstring attmtt aemt l0ve376 \$BLAH_CURRENT CTRL-D\n\n"; my @userinput; chomp( @userinput = ); # Print all choices for user and ask to confirm. # local @Onemore = @userinput; print "\n\nSUMMARY: You have chosen these values: Directory: $DIRN\n File Extension: $Extension\n"; while (@Onemore) { ($Oner) = splice( @Onemore, 0, 1 ); ( $Olds, $News ) = split( /\s+/, $Oner ); chomp($Olds); chomp($News); if ( ( $Olds =~ /^([-\/\@\$\:\w.]+)$/ ) && ( $News =~ /^([-\/\@\$:\w.]+)$/ ) ) { print "String \"$Olds\" to be replaced by \"$News\"\n"; push( @VALIDARRAY, $Olds ); push( @VALIDARRAY, $News ); } else { print "ERROR: Strings \"$Olds\" and/or \"$News\" contain invalid character.\n"; } } print "NOTE: Do you want to proceed (Y|N) (default is N)?\n"; &Raw_Term_Mode; if ( lc("$answer") eq "$def" ) { print "\nNOTE: Aborting global parameter replacement at your request.\n"; exit(0); } die "ERROR: Cannot cd to: $!\n" unless chdir $DIRN; # We are looking for scripts with names $Extension. # if ( defined($Fullsearch) ) { $Findcomm = "find $DIRN -type f -print"; } else { $Findcomm = "find $DIRN -type f -name '\*$Extension' -print"; } open( FIND, "$Findcomm |" ) or die "Cannot find *$Extension files: $!\n"; @find = ; close FIND; foreach $Oldfile (@find) { chomp($Oldfile); if ( !( -T $Oldfile ) ) { print "WARN: \"$Oldfile\" is not a text file. Skipping it...\n"; next; } else { print "\nINFO: Processing file $Oldfile...\n"; } chomp($Oldfile); $Newfile = "${Oldfile}-NEW"; open( OLD, "<$Oldfile" ) or die "ERROR: Can't open $Oldfile: $!"; open( NEW, ">$Newfile" ) or die "ERROR: Can't open $Newfile: $!"; # # Enforce file locks: # Shared lock (1) for reading from an old file. # Advisory exclusive lock (2) for writing into a new file. # flock( OLD, 1 ); flock( NEW, 2 ); while () { $LINE = $_; @Extraarr = @VALIDARRAY; while (@Extraarr) { @Oner = splice( @Extraarr, 0, 2 ); if ( $#Oner != 1 ) { print "ERROR: Record @Oner does not have two words [OLD, NEW]\n"; } else { ( $Oldstring, $Newstring ) = ( @Oner[0], @Oner[1] ); $Oldstring =~ s/([\$])/\\$1/g; $LINE =~ s#$Oldstring#$Newstring#g; } } print NEW $LINE; print "\tNew Line $LINE\n"; } close OLD; close NEW; if ( -T $Newfile && -s $Newfile ) { if ( move( "$Newfile", "$Oldfile" ) ) { chmod 00775, $Oldfile; $cnt = chown $Setpwuid, $Groupowner, $Oldfile; if ( int($cnt) != 1 ) { &Send_warn; } } else { warn "ERROR: Move $Oldfile to $Newfile failed: $!\n"; } } } # POSIX system # #sub I_am_interactive { # local *TTY; # open(TTY, "/dev/tty") or die "Can't open /dev/tty: $!"; # open(TTY, "/dev/tty"); # my $tpgrp = tcgetpgrp(fileno(TTY)); # my $pgrp = getpgrp(); # close(TTY); # print "Woila: it is intercative\n"; # return ($tpgrp == $pgrp); # # We do not want interactive sessions. # # exit(3); #} # non-POSIX system # sub I_am_interactive { return -t STDIN && -t STDOUT; } sub Raw_Term_Mode { ReadMode('cbreak'); $answer = ReadKey(3); ReadMode('normal'); $answer ||= $def; } exit(0);