kirk123 has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I am seriously stuck with problem and I could use some help. I am having problem writing a script that read a text file which contain a list of files that need to be rename or updated if they contain a certain string such as "d25573786-" to "css12345".
The file I am reading from contain the following : c:\\tmp\\05152003.Log c:\\tmp\\d25573786-.Log c:\\tmp\\drwtsn32.log c:\\tmp\\nbenv10 c:\\tmp\\nbenv11 c:\\tmp\\nbenv12 Here a snippet of my script which I ran in the c:\ drive : use strict; use File::Find; use Sys::Hostname; my $fileupdate; my $old_hostname = "d25573786-"; my ($orig,$concat,$new_hostname,$answer); my @lines = " "; my $new_hostname = ""; ## Create new hostname based on physical address ### $new_hostname = shift; if ($new_hostname eq "" ) { $new_hostname = "css12345"; print "Current host name of machine is :$old_hostname \n"; print "The new host name is going to be: $new_hostname\n"; } if ( $old_hostname ne $new_hostname ) { &personalization; } else { print "System already personlized\n"; } chmod( 0777, $orig ); #--------------------------------------------------------------------- +------------------------ sub personalization { open(FH,"<c:\\person.txt") || die "Can't open arp.txt: $!\n"; while(my $line = <FH>) { if( $line =~ /(.*)$old_hostname(.*)/i ) # any files that cont +ain the substring of the old hostname { print "file that match $line\n"; $orig = $line; $concat = $line; $concat =~ s/(.*)$old_hostname(.*)/$1$new_hostname$2/gi; #CALL UPDATE SUBROUTINE rename($orig, $concat) || print "error can't rename $orig + to $concat: $!"; &modified_file($concat); } else { &modified_file($orig ); } } } #--------------------------------------------------------------------- +------------------------ sub modified_file { $fileupdate = shift; open (IN,"<$fileupdate"); @lines = <IN>; close IN; my $change_count = 0; @lines = map { $change_count++ if s/$old_hostname/$new_hostna +me/sgi; $_ } @lines; next unless $change_count; open (OUT,">$fileupdate") || "can't open $fileupdate for writ +ing :$! "; print OUT @lines; close OUT; }
I keep getting the message can't rename, permission denied. If someone have a better script or know how to fix the problem let me know. --thanks

Replies are listed 'Best First'.
Re: Problem with Renaming script
by graff (Chancellor) on May 22, 2003 at 04:42 UTC
    It looks like you may be trying to "rename" the file to a new directory. Are you sure that the new directory has been created at the point where the "rename" is being done?

    Apart from that, it might make more sense to set this process up as a "filter" that will create a new set of files, rather than as an "in-place edit" that will relocate and then modify the files.

    (The filter approach just seems safer -- if you find problems with what the program does, just fix it and run it again, because the original files that it used as input the first time are still where they used to be, and will still have the same contents they originally had, when you run it again.)

    To summarize (in pseudo-perl):

    locate the source directory and get the list of files there establish the name of the destination directory, and create it if nec +essary if $source_dir has subdirectories { create them as needed in the $dest_dir } for $infile ( @sourc_files ) { $outfile = $infile; $outfile =~ s{$source}{$dest}; # might be unnecessary? open(IN,"<","$source_dir/$infile"); open(OUT, ">","$dest_dir/$outfile"); while (<IN>) { s/$source/$dest/g; print OUT; } close IN; close OUT; }
    It shouldn't need to be any more complicated than that (except maybe the initial part of finding the files and subdirectories, but I gather you already solved that part).
      Hi, I am not creating a new directory.
        Oh -- sorry, I must have misunderstood. Well, I wonder if there might be some problem about a file being "open" in some sense when you're trying to rename it, and MSWindows not letting you do that... though the code you showed makes this seem unlikely.

        Still, it might be worthwhile to try a different different approach to the problem. Something like:

        my $oldhostname = "whatever"; my $newhostname = shift || "somethingnew"; die "Nothing to do\n" if ( $oldhostname eq $newhostname ); print "changing $oldhostname to $newhostname\n"; open( FLIST, "<file_containing_list_of_filenames" ) or die "Unable to get list of file names to personalize\n"; my @oldfiles = <FLIST>; chomp @oldfiles; my @renamefiles = grep /$oldhostname/i, @oldfiles; s/$oldhostname/$newhostname/gi for @renamefiles; for my $file ( @oldfiles ) { my $newfile = ( $file =~ /$oldhostname/i ) ? shift @renamefiles : "$file.tmp"; open(IN, "<$file") or die "Unable to read $file: $!\n"; open(OUT, ">$newfile) or die "Can't write $newfile:$!\n; while (<IN>) { s/$oldhostname/$newhostname/gi; print OUT; } close OUT; close IN; unlink $file; rename $newfile, $file if ( $newfile eq "$file.tmp" ); }
        Things to note: (1) if you're going to declare lexically scoped variables with "my", declare each variable as you need it, in the block where it will be used, not globally (which kind of defeats some of the value of lexical scoping).

        (2) This approach uses a different strategy than your original -- since it knows it will need to rewrite every file anyway, it'll use a standard filtering approach, using "newhostname" to set the name of the output file where appropriate, then deleting the old file, and renaming the new one back to the original name if that wasn't supposed to change.

        That's not tested, of course, but assuming that you have already taken care of creating the appropriate list of file names for input to the process, and have the host names the way you want, this should take care of the rest of the task.

        (Personally, if it were my machine, I'd probably want to write all the output files to some separate directory, or at least keep the originals intact somehow, so I could confirm that worked okay before blowing away the originals...)