Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Perl file rename

by keltan (Initiate)
on Jun 02, 2015 at 23:22 UTC ( [id://1128869]=perlquestion: print w/replies, xml ) Need Help??

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

HI

I've got problem i need to write file renamer. I know that there are topics on this forum with answers but i need to write slightly different code and i hope you will help. Yes this is my homework but i dont need direct answers i appreciate tips.
!/usr/bin/perl -w use strict; my $dirname; $dirname = 'D:\test'; my $test = $ARGV[0]; my $test1 = $ARGV[1]; my $pattern = qr/$test/; my $pattern1 = qr/$test1/; opendir(DIR, $dirname) or die "Can't opendir $dirname: $!"; while ( defined (my $file = readdir DIR) ) { next if $file =~ /^\.\.?$/; my $new = $file; $new =~ s/$pattern/$pattern1/; rename($file,$new) }
What i need to write is a script which after this command: ./rename *.pl "s/^/old_/" will add to all files with extension .pl prefix old_ I've been trying few approaches but all failed. Funny thing is that in other languages i don't have that problem only PERL always beat me down.

Replies are listed 'Best First'.
Re: Perl file rename
by aaron_baugher (Curate) on Jun 03, 2015 at 00:26 UTC

    When you run your command at the shell, any unescaped wildcards are expanded according to what files they match. So if there are three files, 1.pl, 2.pl, and 3.pl in the directory, then this:

    ./rename *.pl "s/^/old_/" # will be expanded to this: ./rename 1.pl 2.pl 3.pl s/^/old_/ # and set @ARGV like so: $ARGV[0] == '1.pl'; $ARGV[1] == '2.pl'; $ARGV[2] == '3.pl'; $ARGV[3] == 's/^/old_/';

    So if you want to call it in that order, you have a couple of options. You can escape the asterisk in *.pl with a backslash or by putting it in single quotes, so that the shell will pass it to the script as a single argument, and it'll end up in $ARGV[0] as you expected. The other option is to allow the shell to expand the filenames, then get your regex from the last argument with pop, leaving the filenames in @ARGV:

    my $pattern = pop @ARGV; for my $file (@ARGV){ my $new = $file; # apply pattern and rename }

    If you use the second method, you don't need the opendir/readdir, because the shell is taking care of that for you. That method is probably simpler, but it's less cross-platform since it assumes the shell knows how to do wildcard expansion.

    Aaron B.
    Available for small or large Perl jobs and *nix system administration; see my home node.

      Just to add to that: Perl knows how to do filename expansion too: glob

Re: Perl file rename
by FreeBeerReekingMonk (Deacon) on Jun 02, 2015 at 23:50 UTC

    Writing *.pl in a shell (not sure if CMD too) will expand automatically BEFORE it is handed over to perl's @ARGV, better quote everything!
    Then there is this guy called Larry Wall, he wrote something similar once, take a look: Simple Perl file rename (posted by hilitai).

    Your code almost works.... fight on!

      Writing *.pl in a shell (not sure if CMD too) will expand automatically BEFORE it is handed over to perl's @ARGV, better quote everything!

      No, DOS, Windows, and OS/2 don't behave like Unix at all. That would be far too easy. ;-) See Re^3: Perl Rename for a longer discussion and a workaround.

      Updated: Bad wording. Win32::Autoglob really does not help here (see AM answer below), it only helps hiding one difference between Win32 and Unix systems.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: Perl file rename
by Laurent_R (Canon) on Jun 03, 2015 at 10:13 UTC
    The opendir/readdir combination return to the user filenames without the path to the files (your dirname variable). So that, if your program is not launched from that location, or if you did not chdir to it, your program is not going to work unless you prefix $file and $new with the path.

    Note that the glob built-in will give you filenames with the path.

Re: Perl file rename
by Anonymous Monk on Jun 02, 2015 at 23:39 UTC
Re: Perl file rename
by kcott (Archbishop) on Jun 03, 2015 at 21:20 UTC

    G'day keltan,

    "Yes this is my homework but i dont need direct answers i appreciate tips."

    Thanks for being upfront and honest about that (++). Here's some tips:

    • Consider using the builtin module Getopt::Long for handling your command line arguments.
    • Consider using the warnings pragma instead of the '-w' switch. The documentation explains why.
    • The rename documentation points out some caveats:
      • The portability issues (rename in perlport) mentions "Win32"'D:\test' (in your code) indicates this may be relevant to you.
      • Consider the suggested, platform-independent move() function of the builtin module File::Copy.
    • Avoid package variables for directory handles (DIR in your posted code is an example): these have global scope and suffer from the same problems as all global variables. Prefer lexical variables whose scope you can control — readdir shows a couple of usage examples.
      • Unrelated to your current question but, for future reference, and for the same reasons, avoid package variables for filehandles — open has examples using lexical filehandles.

    -- Ken

Re: Perl file rename
by afoken (Chancellor) on Jun 04, 2015 at 08:05 UTC
    my $pattern = qr/$test/; my $pattern1 = qr/$test1/; # ... $new =~ s/$pattern/$pattern1/;

    I think you have another problem here: The right-hand side of s/// (REPLACEMENT in s/PATTERN/REPLACEMENT/) is not a regular expression, but a string. See Regexp Quote Like Operators. Your use of qr// makes a regular expression from the second argument, then stringifies it. That will very likely give you an unexpected result:

    >perl -e '$x="abc"; $p=qr/b/; $r=qr/X/; $x=~s/$p/$r/; print $x' a(?^:X)c >

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (6)
As of 2024-04-18 15:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found