7

How do I run a Perl script on multiple input files with the same extension?

 perl scriptname.pl file.aspx

I'm looking to have it run for all aspx files in the current directory.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Jake
  • 71
  • 1
  • 1
  • 3

7 Answers7

8

In your Perl file,

 my @files = <*.aspx>;
 for $file (@files) {

      # do something.

 }

The <*.aspx> is called a glob.

  • This works, but is only necessary if you don't have a shell that does the job for you (or the script is launched via a GUI launcher, perhaps) - and is not all that flexible even though it does the job. – Jonathan Leffler Nov 11 '09 at 01:39
  • Thanks for your comment. But rereading the question, I think this answer doesn't need qualification. Also, I would prefer to have the "get all the files with .aspx extension" logic inside the program itself rather than using the command line. –  Nov 11 '09 at 01:57
  • @Jonathan: It's likely that the OP is running on Windows, using the `cmd` shell. As far as I remember, `cmd` does not do wildcard expansion as Unix shells do. – C. K. Young Nov 11 '09 at 02:03
  • @Jonathan: also there can be problems if the number of files is too big. – larelogio Nov 11 '09 at 14:11
  • 3
    You don't need to tell people that <*.aspx> is a glob is you just use glob('*.aspx') at the start. :) – brian d foy Nov 11 '09 at 18:01
  • I knew somebody would say that. –  Nov 12 '09 at 00:24
3

For a simple one-liner with -n or -p, you want

perl -i~ -pe 's/foo/bar/' *.aspx

The -i~ says to modify each target file in place, and leave the original as a backup with an ~ suffix added to the file name. (Omit the suffix to not leave a backup. But if you are still learning or experimenting, that's a bad idea; removing the backups when you're done is a much smaller hassle than restoring the originals from a backup if you mess something up.)

Of course, if you want the Perl script to write output to standard output, and not modify the files, don't put the -i option at all.

If your Perl code is too complex for a one-liner (or just useful enough to be reusable) obviously replace -e '# your code here' with scriptname.pl ... though then maybe refactor scriptname.pl so that it accepts a list of file name arguments, and simply use scriptname.pl *.aspx to run it on all *.aspx files in the current directory.

If you need to recurse a directory structure and find all files with a particular naming pattern, the find utility is useful.

find . -name '*.aspx' -exec perl -pi~ -e 's/foo/bar/' {} +

If your find does not support -exec ... + try with -exec ... \; though it will be slower and launch more processes (one per file you find instead of as few as possible to process all the files).

To only scan some directories, replace . (which names the current directory) with a space-separated list of the directories to examine, or even use find to find the directories themselves (and then perhaps explore -execdir for doing something in each directory that find selects with your complex, intricate, business-critical, maybe secret list of find option predicates).

Maybe also explore find2perl to do this directory recursion natively in Perl.

In case it's not obvious, -pi~ is a condensed way to write -p -i~; this is called "option clustering".

tripleee
  • 175,061
  • 34
  • 275
  • 318
2

If you are on Linux machine, you could try something like this.

for i in `ls /tmp/*.aspx`; do perl scriptname.pl $i; done
bichonfrise74
  • 1,987
  • 4
  • 16
  • 11
  • 2
    useless use of ls. -- for i in /tmp/* – ghostdog74 Nov 11 '09 at 01:36
  • Actually, it should be `./*.aspx` to answer the question. – Jonathan Leffler Nov 11 '09 at 01:37
  • I find using ls very useful for cases that you want to process the files in a certain order. For example, ls -tr ./*.aspx will run the perl script on all files in the order they were modified. – Ari May 16 '13 at 20:41
  • And of course simply `perl scriptname.pl *.aspx` should work if `scriptname.pl` is written to handle a list of input file names. – tripleee Apr 13 '17 at 04:42
  • @Ari What exactly is the use case for preserving the modification order? If the Perl script executes in a reasonable time the files will be all be modified in the same second anyway, or a sequence of adjacent seconds if the script is somewhat slow or there are many files (or nonadjacent if the script is really slow, but then if it's significant work, are you brave enough to run it automated?) A good workaround without the [various well-documented perils of `ls`](http://mywiki.wooledge.org/ParsingLs) is to use `find` with suitable options if you really need this. – tripleee Jan 04 '18 at 05:17
2

you can pass those files to perl with wildcard

in your script

foreach (@ARGV){
    print "file: $_\n";
    # open your file here...
       #..do something
    # close your file
}

on command line

$ perl myscript.pl *.aspx
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
2

You can use glob explicitly, to use shell parameters without depending to much on the shell behaviour.

for my $file ( map {glob($_)} @ARGV ) { 
   print $file, "\n";
};

You may need to control the possibility of a filename duplicate with more than one parameter expanded.

larelogio
  • 390
  • 2
  • 6
0

For example to handle perl scriptname.pl *.aspx *.asp

In linux: The shell expands wildcards, so the perl can simply be

for (@ARGV) {
  operation($_); # do something with each file
}

Windows doesn't expand wildcards so expand the wildcards in each argument in perl as follows. The for loop then processes each file in the same way as above

for (map {glob} @ARGV) {
  operation($_); # do something with each file
}

For example, this will print the expanded list under Windows

print "$_\n" for(map {glob} @ARGV);
-2

You can also pass the path where you have your aspx files and read them one by one.

#!/usr/bin/perl -w

use strict;

my $path = shift;
my @files = split/\n/, `ls *.aspx`;

foreach my $file (@files) {
        do something...
}
Space
  • 7,049
  • 6
  • 49
  • 68
  • 1
    You don't need to shell out to ls, which might not even be a valid command on some systems. – brian d foy Nov 11 '09 at 18:03
  • Even on systems where `ls` is available, it is the wrong tool to use here, and has [multiple well-documented issues](http://mywiki.wooledge.org/ParsingLs). Perl has globbing built-in so simply `foreach my $file (<*.aspx>)` or if your needs are somewhat more complex, as a skeleton for the code, `opendir` the directory and loop over files, doing `next unless /\.aspx$/` at the top of inside the loop. – tripleee Jan 04 '18 at 05:38