use Config; use File::Basename qw(basename dirname); ($VERSION)=' $Id: rename.PL,v 1.8 2010/09/19 18:16:39 peder Exp $ '=~/v\s*(\d+(?:\.\d+)+)/; chdir(dirname($0)); ($file = basename($0)) =~ s/\.PL$//; $file =~ s/\.pl$// if ($Config{'osname'} eq 'VMS' or $Config{'osname'} eq 'OS2'); # "case-forgiving" open OUT,">$file" or die "Can't create $file: $!"; chmod(0755, $file); print "Extracting $file\n"; print OUT <<"!DO!SUBST!"; $Config{'startperl'} #line 18 use strict; use Getopt::Long; use Text::Abbrev; use File::Basename; my \$VERSION = '$VERSION'; !DO!SUBST! print OUT<<'!NO!SUBST!'; Getopt::Long::config(qw(bundling)); $Getopt::Long::prefix = '--'; my $ME = $0; ($ME = $0) =~ s!.*/!!; $| = 1; my $opt_dryrun = 0; my $opt_backup = 0; my $opt_force = 0; my $opt_interactive = 0; my $opt_verbose = 0; my $opt_help = 0; my $opt_version = 0; my $opt_linkonly = 0; my $opt_prefix = ''; my $opt_suffix = ''; my $opt_basename_prefix = ''; my $opt_vcm = $ENV{RENAME_VERSION_CONTROL} || $ENV{VERSION_CONTROL} || 'existing'; sub VCM_SIMPLE { 0 } sub VCM_TEST { 1 } sub VCM_NUMBERED { 2 } my $vcm; sub error { my($ERROR) = @_; print "$ME: $ERROR\n"; print "Try `$ME --help' for more information.\n"; exit 1; } { local $SIG{__WARN__} = sub { if ($_[0] =~ /^Unknown option: (\S+)/) { error("unrecognized option `--$1'"); } else { print @_; } }; GetOptions( 'b|backup' => \$opt_backup, 'B|prefix=s' => \$opt_prefix, 'f|force' => \$opt_force, 'h|help' => \$opt_help, 'i|interactive' => \$opt_interactive, 'l|link-only' => \$opt_linkonly, 'n|just-print|dry-run' => \$opt_dryrun, 'version' => \$opt_version, 'v|verbose' => \$opt_verbose, 'V|version-control=s' => \$opt_vcm, 'Y|basename-prefix=s' => \$opt_basename_prefix, 'z|S|suffix=s' => \$opt_suffix, ); } if ($opt_version) { print "$ME $VERSION\n"; exit 0; } if ($opt_help) { print< VCM_TEST, existing => VCM_TEST, t => VCM_NUMBERED, numbered => VCM_NUMBERED, never => VCM_SIMPLE, simple => VCM_SIMPLE, }}{$vcm}; } $opt_suffix ||= $ENV{SIMPLE_BACKUP_SUFFIX} || '~'; } my $op = shift or error('missing arguments'); if (!@ARGV) { @ARGV = ; chomp(@ARGV); } for (@ARGV) { my $was = $_; { no strict; eval $op; } die $@ if $@; next if $was eq $_; if (-e $_) { unless ($opt_force) { if (! -w && -t) { printf "%s: overwrite `%s', overriding mode 0%03o? ", $ME, $_, (stat _)[2]&0777; next unless =~ /^y/i; } elsif ($opt_interactive) { print "$ME: replace `$_'? "; next unless =~ /^y/i; } } if ($opt_backup) { my $old; if ($vcm == VCM_SIMPLE) { if (m,^(.*/)?(.*),) { $old = "$opt_prefix$1$opt_basename_prefix$2$opt_suffix"; } } else { ($old) = sort {($b=~/~(\d+)~$/)[0] <=> ($a=~/~(\d+)~$/)[0]} <$_.~*~>; $old =~ s/~(\d+)~$/'~'.($1+1).'~'/e; if ($vcm == VCM_TEST) { unless ($old) { if (m,^(.*/)?(.*),) { $old = "$opt_prefix$1$opt_basename_prefix$2$opt_suffix"; } } } elsif ($vcm == VCM_NUMBERED) { $old ||= "$_.~1~"; } } print "backup: $_ -> $old\n" if $opt_verbose && $opt_dryrun; unless ($opt_dryrun) { if ($old =~ m,/,) { my $dir = File::Basename::dirname($old); unless (-d $dir) { if ($opt_dryrun) { print "mkdir: $dir\n" if $opt_verbose; } else { mkpath($dir) || next; } } } unless (rename($_,$old)) { warn "$ME: cannot create `$old': $!\n"; next; } } } } print "$was ", $opt_linkonly ? "=" : '-', "> $_\n" if $opt_verbose || $opt_dryrun; if (m,/,) { my $dir = File::Basename::dirname($_); unless (-d $dir) { if ($opt_dryrun) { print "mkdir: $dir\n" if $opt_verbose; } else { mkpath($dir) || next; } } } unless ($opt_dryrun) { if ($opt_linkonly) { link($was,$_) || warn "$ME: cannot create `$_': $!\n"; } else { rename($was,$_) || warn "$ME: cannot create `$_': $!\n"; } } } sub mkpath { my($path) = @_; $path .= '/' if $^O eq 'os2' and $path =~ /^\w:\z/s; # feature of CRT # Logic wants Unix paths, so go with the flow. if ($^O eq 'VMS') { next if $path eq '/'; $path = VMS::Filespec::unixify($path); if ($path =~ m:^(/[^/]+)/?\z:) { $path = $1.'/000000'; } } return 1 if -d $path; my $parent = File::Basename::dirname($path); unless (-d $parent or $path eq $parent) { mkpath($parent) || return; } #print "mkdir: $path\n" if $opt_verbose; unless (mkdir($path, 0777)) { unless (-d $path) { warn "$ME: cannot mkdir `$path': $!\n"; return; } } return 1; } __END__ =head1 NAME rename - renames multiple files =head1 SYNOPSIS B [B<-bfilnv>] [B<-B> I] [B<-S> I] [B<-V> I] [B<-Y> I] [B<-z> I] [B<--backup>] [B<--basename-prefix=>I] [B<--dry-run>] [B<--force>] [B<--help>] [B<--interactive>] [B<--just-print>] [B<--link-only>] [B<--prefix=>I] [B<--suffix=>I] [B<--verbose>] [B<--version-control=>I] [B<--version>] I [F]... =head1 DESCRIPTION I renames the filenames supplied according to the rule specified as the first argument. The argument is a Perl expression which is expected to modify the $_ string 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. If a destination file is unwritable, the standard input is a tty, and the B<-f> or B<--force> option is not given, mv prompts the user for whether to overwrite the file. If the response does not begin with `y' or `Y', the file is skipped. =head1 OPTIONS =over 4 =item B<-b>, B<--backup> Make backup files. That is, when about to overwrite a file, rename the original instead of removing it. See the B<-V> or B<--version-control> option fo details about how backup file names are determined. =item B<-B> I, B<--prefix=>I Use the B method to determine backup file names (see the B<-V> I or B<--version-control=>I option), and prepend I to a file name when generating its backup file name. =item B<-f>, B<--force> Remove existing destination files and never prompt the user. =item B<-h>, B<--help> Print a summary of options and exit. =item B<-i>, B<--interactive> Prompt whether to overwrite each destination file that already exists. If the response does not begin with `y' or `Y', the file is skipped. =item B<-l>, B<--link-only> Link files to the new names instead of renaming them. This will keep the original files. =item B<-n>, B<--just-print>, B<--dry-run> Do everything but the actual renaming, insted just print the name of each file that would be renamed. When used together with B<--verbose>, also print names of backups (which may or may not be correct depending on previous renaming). =item B<-v>, B<--verbose> Print the name of each file before renaming it. =item B<-V> I, B<--version-control=>I Use I to determine backup file names. The method can also be given by the B (or if that's not set, the B) environment variable, which is overridden by this option. This option does not affect wheter backup files are made; it affects only the name of any backup files that are made. The value of I is like the GNU Emacs `version-control' variable; B also recognize synonyms that are more descriptive. The valid values are (unique abbreviations are accepted): =over =item B or B Make numbered backups of files that already have them, otherwise simple backups. This is the default. =item B or B Make numbered backups. The numbered backup file name for I is B.~I~> where I is the version number. =item B or B Make simple backups. The B<-B> or B<--prefix>, B<-Y> or B<--basename-prefix>, and B<-z> or B<--suffix> options specify the simple backup file name. If none of these options are given, then a simple backup suffix is used, either the value of B environment variable if set, or B<~> otherwise. =back =item B<--version> Print version information on standard output then exit successfully. =item B<-Y> I, B<--basename-prefix=>I Use the B method to determine backup file names (see the B<-V> I or B<--version-control=>I option), and prefix I to the basename of a file name when generating its backup file name. For example, with B<-Y .del/> the simple backup file name for B is B. =item B<-z> I, B<-S> I, B<--suffix=>I Use the B method to determine backup file names (see the B<-V> I or B<--version-control=>I option), and append I to a file name when generating its backup file name. =back =head1 EXAMPLES To rename all files matching *.bak to strip the extension, you might say rename 's/\e.bak$//' *.bak To translate uppercase names to lower, you'd use rename 'y/A-Z/a-z/' * More examples: rename 's/\.flip$/.flop/' # rename *.flip to *.flop rename s/flip/flop/ # rename *flip* to *flop* rename 's/^s\.(.*)/$1.X/' # switch sccs filenames around rename 's/$/.orig/ */*.[ch]' # add .orig to source files in */ rename 'y/A-Z/a-z/' # lowercase all filenames in . rename 'y/A-Z/a-z/ if -B' # same, but just binaries! or even rename chop *~ # restore all ~ backup files =head1 ENVIRONMENT Two environment variables are used, B and B. See L. =head1 SEE ALSO mv(1) and perl(1) =head1 DIAGNOSTICS If you give an invalid Perl expression you'll get a syntax error. =head1 AUTHOR Peder Stray , original script from Larry Wall. =cut !NO!SUBST!