in reply to Re: Simple Perl file rename
in thread Simple Perl file rename

Hiya,

I am trying to understand Larry's filename fixer. I saw it first in the cookbook and am now looking here to find help. I am new to Perl, but I think (I hope) I understand everything the script does. The only thing I don't get is how all the matching filenames end up in @ARGV. So if I call the rename script in a directory with three txt files like so:

rename 's/foo/bar/' *.txt

@ARGV would be an Array with four entries like this right?

s/foo/bar/\n
file1.txt\n
fiel2.txt\n
file3.txt\n

after the shift that removes the 's/foo/bar/' I am then left with the @ARGV that contains just the file names. The script then loops through all of them and works it's magic, so far so good.

What I do not understand is how the script determines which files to put into @ARGV. At which point is "*.txt" being evaluated? Or is it the shell that tells the script which files in the directory match the pattern *.txt?

This is probably a daft question but any help is much appreciated, as I said I am very new to this.


Ta Arian

Replies are listed 'Best First'.
Re^3: Simple Perl file rename
by wnpaul (Initiate) on Aug 03, 2008 at 05:38 UTC

    In any UNIX-like shell, when you specify a filename glob (i.e. a filename with wildcards) on the shell commandline, it is the shell, and not the program you are calling, which expands the glob.

    So yes, when you call

    rename.pl *.txt
    the shell expands the *.txt to all matching files, and the Perl script finds the already expanded args in its @ARGV.

    If you want the script to do the glob expansion, you'd have to enclose the argument in single quotes, i.e. call it like this:

    somescript.pl '*.txt'

    Then the Perl script finds exactly one arg in @ARGV, namely *.txt and you would have to find some way to do the expansion.

    With Larry's script however, I typically feed it ALL the files by matching *; it will only act on those files which max the regexp given as the first argument anyway, all others are skipped. Of course that requires some care in constructing the regexp.

Re^3: Simple Perl file rename
by toolic (Bishop) on Jul 28, 2008 at 18:31 UTC
    @ARGV would be an Array with four entries like this right?
    Yes, except for the new lines, \n. Prove this to yourself with a test script:
    use strict; use warnings; print "These are the ", scalar @ARGV, " arguments:\n"; my $i = 0; for (@ARGV) { print "ARGV[$i] = $_\n"; $i++; }

    prints:

    These are the 4 arguments: ARGV[0] = s/foo/bar/ ARGV[1] = file1.txt ARGV[2] = file2.txt ARGV[3] = file3.txt

    Alternately, you can use Data::Dumper:

    use strict; use warnings; use Data::Dumper; print Dumper(\@ARGV);

    prints:

    $VAR1 = [ 's/foo/bar/', 'file1.txt', 'file2.txt', 'file3.txt' ];
    What I do not understand is how the script determines which files to put into @ARGV. At which point is "*.txt" being evaluated? Or is it the shell that tells the script which files in the directory match the pattern *.txt?
    The shift built-in function removes element 0 from the @ARGV array, shifting the remaining elements [1:3] down to new positions [0:2]. Again, here is a simple test script:
    use strict; use warnings; my $op = shift; # same as: my $op = shift @ARGV; print "These are the ", scalar @ARGV, " arguments:\n"; my $i = 0; for (@ARGV) { print "ARGV[$i] = $_\n"; $i++; }

    prints:

    These are the 3 arguments: ARGV[0] = file1.txt ARGV[1] = file2.txt ARGV[2] = file3.txt
      Hi toolic,

      thank you for your quick reply. I understand what shift does in this script. What I don't understand is how all txt files in the directory end up in @ARGV.

      When I copy and paste your code, what I get is:

      These are the 2 arguments: ARGV[0] = s/\.txt\.mex// ARGV[1] = *.txt

      And this also makes sense to me, because how would the script be able to know which files in the directory match '*.txt'? Doesn't there have to be another process that matches '*.txt' against all files in the directory first?

      Arian
        When I copy and paste your code
        Since I provided 3 sets of code and output data, I am not sure which one you ran.

        Let's try another approach...

        > ls *.txt file1.txt file2.txt file3.txt > cat test.pl #!/usr/bin/env perl use strict; use warnings; use Data::Dumper; print Dumper(\@ARGV); > ./test.pl 's/foo/bar/' file*.txt $VAR1 = [ 's/foo/bar/', 'file1.txt', 'file2.txt', 'file3.txt' ]; >

        My operating system in Linux. I have 3 *.txt files in my current directory. When I run my test.pl script, it simply prints out the contents of the @ARGV array, which correspond to the things which appear on the test.pl command line. The 1st thing on the command line is the string corresponding to the substitution operator. The 2nd thing on the command line is a file specifier using the standard Unix wildcard character (*), which gets expanded into 3 filenames.

        Are you on a *nix OS, or are you on Windows, or a Mac?

        Are you familiar with the concept of wildcard expansion?

        sorry for the mistake in the 's///' bit, but it doesn't change the result