Skip to content

Instantly share code, notes, and snippets.

@fsiler
Last active July 19, 2016 19:04
Show Gist options
  • Save fsiler/9954002c148fe8cfb6be2a255c95f2c7 to your computer and use it in GitHub Desktop.
Save fsiler/9954002c148fe8cfb6be2a255c95f2c7 to your computer and use it in GitHub Desktop.
classic Perl rename script with verbose, no-action, and updated to add undo file
#!/usr/bin/env perl -w
#
# This script was developed by Robin Barker ([email protected]),
# 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.
#
# 20160717 [email protected] revised- added automatic UNDO script creation
# 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;
if (!@ARGV) {
print "reading filenames from STDIN\n" if $verbose;
@ARGV = <STDIN>;
chop(@ARGV);
}
(open UNDO, ">", glob("~/.undo_rename") or die "Cannot open undo file.") unless $no_act;
for (@ARGV) {
my $was = $_;
eval $op;
die $@ if $@;
next if $was eq $_; # ignore quietly when rename matches current name
if (-e $_ and !$force)
{
warn "$was not renamed: $_ already exists\n";
}
elsif ($no_act)
{
print "$was would be renamed to $_\n";
}
elsif (rename $was, $_)
{
print "$was renamed as $_\n" if $verbose;
print UNDO "mv \"$_\" \"$was\"\n";
}
else
{
warn "Can't rename $was $_: $!\n";
}
}
close UNDO
__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.
Any changes made can be undone by sourcing ~/.undo_rename.
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment