http://www.perlmonks.org?node_id=764541

Sometimes you have a really repetitive task to do on a bunch of files. Sound familiar? You first need to specify the files, then you need to do the same operation on each one. The shell's traditional pipeline can nicely collect the paths, and then use the perl one-liner to do the operation.

Real life example: I needed to identify all the zipfiles in a directory tree and delete all *.exe files hiding inside the zipfiles.

First collect the files:

du -b */*/old.zip | sort -n | xcol 1 >oldfiles
This shows all the zipfiles that were in subdirectories of subdirectories, then sorts them for size so I can decide to leave out the small ones. xcol is a perl script I posted to Code section to extract the column of filenames to file oldfiles.

Then use this perl one-liner:

perl -e 'while (<>) { chop; system qq{zip -d "$_" "*exe*"} }' oldfiles

Love that Perl!

HTH,
SSF

Replies are listed 'Best First'.
Re: multiple file operations using perl one-liners
by ikegami (Patriarch) on May 17, 2009 at 19:37 UTC

    Safer and no longer:

    perl -e'while(<>) { chomp; system zip => "-d", $_, "*exe*" }' oldfiles

    Error checking (like a simple '-Mautodie' or 'or die "system: $?\n"') wouldn't hurt either.

Re: multiple file operations using perl one-liners
by graff (Chancellor) on May 18, 2009 at 06:18 UTC
    In terms of doing shell commands on a list of items, you might want to check out this old thing that I posted here long ago. It has saved me uncountable hours of time over the years in doing routine shell stuff on arbitrary sets of files -- I still use it daily: shloop -- execute shell command on a list.
Re: multiple file operations using perl one-liners
by morgon (Priest) on May 17, 2009 at 19:43 UTC
    Am I missing something or is this far too complicated?

    Why are you sorting your files when you want to process all of them anyway?

    And I can't see a real reason for your "xcol" or an intermediate file, you can do all of it one go like this (-n does the looping here):

    du -b */*/old.zip | perl -ne 'chomp; my $f = (split /t/)[1]; system qq +{zip -d $f "*exe*"}'
      -n + chomp can be replaced with -nl.

      That should be /\t/, I think? -a would be better than split

      du -b */*/old.zip | perl -F\\t -lane'system zip => "-d", $F[1], "*exe* +"'

      Or shorter and simpler yet:

      du -b */*/old.zip | perl -ne'system zip => "-d", /\t(.*)/, "*exe*"'

      My earlier comment on error checking still applies.

        That last one totally rocks, Ikegami!

        I always learn something when I post here.

        SSF

        -n + chomp can be replaced with -nl
        Thanks - quite useful to know.

        Gotta re-read the perlrun-manpage.

        Or:

        perl -e'system zip => -d => /\t(.*)/, "*exe*" for `du -b */*/old.zip`'