[Gllug] Poor scripting?!

John Edwards john at cornerstonelinux.co.uk
Wed Mar 12 13:09:22 UTC 2008


On Wed, Mar 12, 2008 at 07:51:22AM +0000, Henrik Morsing wrote:
> On Tue, Mar 11, 2008 at 03:36:27PM +0000, John Edwards wrote:
>> 
>> Is there any reason you aren't using Perl's own rename program?
>> 
>> find . -iname "*pattern*" -print0 | xargs -r0 rename 's/pattern/replacement/g'
>> 
>> Of course you may have too many directories for rename to process as
>> arguments. It certain works with several thousand.

> Well, just looked at this and a couple of reasons, one being that I
> don't seem to have that rename program :)

Yes, it doesn't seem to be in the stock Perl tarball but it is
included in the Debian package. Google didn't find the original,
and Debian keeps in a 9000+ line diff file:
    http://packages.debian.org/stable/perl

As it's less than a hundred lines of code, I've attached it so you can
use it as a reference. I hope that won't offend others on the mailing
list.


> The other is that with this option I'd have to run find twice (for
> the two different patterns) and running find seems to be what takes
> time.

The GNU version of find can search for multiple patterns with the 
-o OR option:
    find /dir/ -iname "*pattern1*" -o  -iname "*pattern2*"

Then the regex for rename will contain both substitutions: 
    find /dir/ -iname "*pattern1*" -o  -iname "*pattern2*" -print0 | \
        xargs -r0 rename 's/pattern1/replace/g ; s/pattern2/replace/g'


> If I run my dedicated Perl script it only needs to run find once
> which takes less than 2 minutes.

The find/xargs method shouldn't take much longer than that for a small
(less than a thousand) number of directories that need to be changed.


> I counted the directories btw and out of 3300 directories it will
> typically change about 60 of them.

Both the find/xargs and pure perl solutions should be able to do that
in a matter of minutes.


Using a dedicated Perl script would allow you include some extra
logging and debugging if you need it. Disadvantage is that like
many Perl scripts it may become hard to maintain over time.

Unless the script is performing a very important function I would go
with whichever is easier for your sysadmins to be comfortable with.


-- 
#---------------------------------------------------------#
|    John Edwards   Email: john at cornerstonelinux.co.uk    |
|                                                         |
| A. Because it breaks the logical sequence of discussion |
| Q. Why is top posting bad ?                             |
#---------------------------------------------------------#
-------------- next part --------------
#!/usr/bin/perl -w
#
#  This script was developed by Robin Barker (Robin.Barker at npl.co.uk),
#  from Larry Wall's original script eg/rename from the perl source.
#
#  This script is free software; you can redistribute it and/or modify it
#  under the same terms as Perl itself.
#
# Larry(?)'s RCS header:
#  RCSfile: rename,v   Revision: 4.1   Date: 92/08/07 17:20:30 
#
# $RCSfile: rename,v $$Revision: 1.5 $$Date: 1998/12/18 16:16:31 $
#
# $Log: rename,v $
# Revision 1.5  1998/12/18 16:16:31  rmb1
# moved to perl/source
# changed man documentation to POD
#
# Revision 1.4  1997/02/27  17:19:26  rmb1
# corrected usage string
#
# Revision 1.3  1997/02/27  16:39:07  rmb1
# added -v
#
# Revision 1.2  1997/02/27  16:15:40  rmb1
# *** empty log message ***
#
# Revision 1.1  1997/02/27  15:48:51  rmb1
# Initial revision
#

use strict;

use Getopt::Long;
Getopt::Long::Configure('bundling');

my ($verbose, $no_act, $force, $op);

die "Usage: rename [-v] [-n] [-f] perlexpr [filenames]\n"
    unless GetOptions(
	'v|verbose' => \$verbose,
	'n|no-act'  => \$no_act,
	'f|force'   => \$force,
    ) and $op = shift;

$verbose++ if $no_act;

if (!@ARGV) {
    print "reading filenames from STDIN\n" if $verbose;
    @ARGV = <STDIN>;
    chop(@ARGV);
}

for (@ARGV) {
    my $was = $_;
    eval $op;
    die $@ if $@;
    next if $was eq $_; # ignore quietly
    if (-e $_ and !$force)
    {
	warn  "$was not renamed: $_ already exists\n";
    }
    elsif ($no_act or rename $was, $_)
    {
	print "$was renamed as $_\n" if $verbose;
    }
    else
    {
	warn  "Can't rename $was $_: $!\n";
    }
}

__END__

=head1 NAME

rename - renames multiple files

=head1 SYNOPSIS

B<rename> S<[ B<-v> ]> S<[ B<-n> ]> S<[ B<-f> ]> I<perlexpr> S<[ I<files> ]>

=head1 DESCRIPTION

C<rename>
renames the filenames supplied according to the rule specified as the
first argument.
The I<perlexpr> 
argument is a Perl expression which is expected to modify the C<$_>
string in Perl for at least some of the filenames specified.
If a given filename is not modified by the expression, it will not be
renamed.
If no filenames are given on the command line, filenames will be read
via standard input.

For example, to rename all files matching C<*.bak> to strip the extension,
you might say

	rename 's/\.bak$//' *.bak

To translate uppercase names to lower, you'd use

	rename 'y/A-Z/a-z/' *

=head1 OPTIONS

=over 8

=item B<-v>, B<--verbose>

Verbose: print names of files successfully renamed.

=item B<-n>, B<--no-act>

No Action: show what files would have been renamed.

=item B<-f>, B<--force>

Force: overwrite existing files.

=back

=head1 ENVIRONMENT

No environment variables are used.

=head1 AUTHOR

Larry Wall

=head1 SEE ALSO

mv(1), perl(1)

=head1 DIAGNOSTICS

If you give an invalid Perl expression you'll get a syntax error.

=head1 BUGS

The original C<rename> did not check for the existence of target filenames,
so had to be used with care.  I hope I've fixed that (Robin Barker).

=cut
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 196 bytes
Desc: Digital signature
URL: <http://mailman.lug.org.uk/pipermail/gllug/attachments/20080312/f1871242/attachment.pgp>
-------------- next part --------------
-- 
Gllug mailing list  -  Gllug at gllug.org.uk
http://lists.gllug.org.uk/mailman/listinfo/gllug


More information about the GLLUG mailing list