Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Odd file rename

by Anonymous Monk
on Jun 14, 2000 at 16:18 UTC ( [id://18077]=perlquestion: print w/replies, xml ) Need Help??

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

I need to rename files using Perl - they are tested to see if they fit certain criteria (this part I have down), and then renamed. The rename needs to take the first character and replace it with another character, leaving the rest of the filename alone.

Ex: Testfile -> Bestfile or something of the sort. Any ideas?

Replies are listed 'Best First'.
RE: Odd file rename
by jjhorner (Hermit) on Jun 14, 2000 at 17:33 UTC

    Here is a decent solution:

    #!/usr/bin/perl -w foreach (@ARGV){ $name = $_ ; $name =~ s/T/B/; rename($_, $name); print "$_ renamed to $name\n"; }

    Usage: changename.pl T*

    I hope this helps.

    J. J. Horner
    Linux, Perl, Apache, Stronghold, Unix
    jhorner@knoxlug.org http://www.knoxlug.org/
    
Re: Odd file rename
by lhoward (Vicar) on Jun 14, 2000 at 16:27 UTC
    Just use a regular expression to modify the first character.
    my $oldfilename='Testfile'; my $newfilename=$oldfilename; $newfilename=~s/^./B/; # # another option instead of the regular expression would # be to assign to a substr... This will probably be slightly # faster # # substr($newfilename,0,1)='B'; # link $oldfilename, $newfilename or die "link error $!"; unlink $oldfilename or die "unlink error $!";
    note the "link/unlink" that I do will not work under NT
RE: Odd file rename
by muppetBoy (Pilgrim) on Jun 14, 2000 at 16:32 UTC
    You could, for the last part of lhowards answer use
    rename OLDNAME, NEWNAME
    instead of the link/unlink block - Although his answer is more robust if your OS supports it.
    Update:I think Corion is correct, its been a long day.... I was thinking vaguely of the possibility of a race condition when using rename if another process is attempting to read the file. Is this possible? and if it is would flock sort things out. Also error handling would/could be better with the link/unlink method.

      To be honest, I don't see where rename() would be less robust than the link() / unlink() combo. Both cases work only on the same file system, both cases do otherwise the Right Thing, except that rename() is atomic, where link / unlink are two different statements. In the case of failure, both statements leave the original file untouched, but if the unlink() fails, you are left with an additional link to the old file, which is not always what you want ...

      Update : And even Larry Wall claims that rename is cool :

      Besides, REAL computers have a rename() system call. :-)

        I proposed the link/unlink solution because IMHO it allows for finer granularity of error handling (not that my example took advantage of this, but I could have). Also, according to this earlier perlmonks article rename a user was experiencing rename failures which ended up deleting the file being renamed.

        Of course, this shouldn't be an issue if the perl rename function really just calls the system rename call. I guess this depends on which OS you are running.

RE: Odd file rename
by Anonymous Monk on Jun 14, 2000 at 17:25 UTC
    Names changed to protect the guilty - can I do this while the file is open, or do I need to close it first? Please excuse my hideous indentation, it's a work in progress.
    #!/usr/bin/perl @incoming = ( `ls /home/user/perl/testincoming` ); foreach $directory (@incoming) { chomp($directory); @files = ( `ls /home/user/perl/testincoming/$directory` ); foreach $file (@files) { $pattern = "PGP"; open(FILE,"/home/user/perl/testincoming/$directory/$file") or +die "Could n't open $file"; while (<FILE>) { if (/\Q$pattern\E/) { my $newname=$file; $newname=~s/^./o/; rename ($file, $newname); } close FILE; } } }

      Doing stuff like moving open files is mostly asking for trouble. Under UNIX systems, this shouldn't be a problem (but who can tell for all UNIX systems ?), under NT this will work and under Windows 9x you will get a sharing violation.

      The best thing is to do the rename afterwards, and it's not really hard to do this either.

      Untested code coming...
      #!/usr/bin/perl my $pattern = "PGP"; &renameFiles('/home/user/perl/testincoming'); sub renameFiles { # Pass directory name as parameter my $Dir = shift; opendir(DIR, $Dir) || die "Can't opendir $Dir: $!"; my @Files = grep { -f "$Dir/$_" } readdir(DIR); rewinddir(DIR); my @Dirs = grep { /^[^.].*/ && -d "$Dir/$_" && ! -l "$Dir/$_"} rea +ddir(DIR); closedir DIR; foreach $file (@Files) { open(FILE,"<$Dir/$file") || die "Can't open $file: $!"; my $doRename=0; READFILE: while (<FILE>) { if (/\Q$pattern\E/) { $doRename=1; last READFILE; } } close(FILE); if ($doRename) { my $newname=$file; $newname=~s/^./o/; rename ("$Dir/$file", "$Dir/$newname"); } } # Call self for each subdir foreach $SubDir (@Dirs) { &renameFiles(join("/",$Dir,$SubDir)); } };
      Should rename all files containing a PGP line in the whole subdirectory tree. This is just a quick modify of something I already had, so it may contain bugs, etc...
      I'm not responsible for what it does to your system, no warraty, etc, etc. You know the standard phrases.

      UPDATE:As merlyn humbly suggests in his post, I now check for symlinks with && ! -l "$Dir/$_". The code is still untested from my part.

      /brother t0mas
      A reply falls below the community's threshold of quality. You may see it by logging in.
RE: Odd file rename
by Anonymous Monk on Jun 14, 2000 at 17:02 UTC
    The only problem with using $oldname $newname is that I will be doing this automatically for a large number of files, and the names for each will be different - though the naming convention will be the same for all of them.

    F1234 -> B1234
    F2345 -> B2345
    F3456 -> B3456

    I guess that didn't quite come through in my initial explanation. =)

      I really can't see your problem with that. Try:
      my @fileList=("F1234","F2345","F3456"); foreach $oldname (@fileList) { $newname=$oldname; $newname=~ s/^./B/i; rename($oldname,$newname) };
      (credits for regexp to lhoward)

      /brother t0mas

      the first part of the post you are referring to tells you how to set $oldname and $newname to something sensible before you do the link/unlink operation. Granted there is a large comment in the middle, but that merely discusses an alternative method for setting $oldname and $newname.

      Please read it again, you will see that you did come over correctly and they have indeed answered your question.

      Nuance

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://18077]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (3)
As of 2024-04-19 23:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found