1
0
.dotfiles/home/bin/rre

290 lines
6.7 KiB
Perl
Executable File

#!/usr/bin/perl -w
# rre - A rename command that supports regular expressions.
#
# See `rre -?` for help.
#
# --Kirsle
# http://sh.kirsle.net/
use strict;
use warnings;
use Getopt::Long;
Getopt::Long::Configure ("bundling");
our $VERSION = '0.01';
my $help = 0; # using --help flag
my $recurse = 0; # using -R flag
my $verbose = 0; # using -v flag
my $force = 0; # using -f flag
my $replace = ''; # using -r flag
my $input = ''; # input RE
my $output = ''; # output RE
my $limit = 250; # renaming limit for uniqueness
# Get the options.
my $getopts = GetOptions (
'help|h|?' => \$help,
'R|recursive|recurse' => \$recurse,
'v|verbose' => \$verbose,
'l|limit' => \$limit,
'f|force' => \$force,
'r|replace' => \$replace,
'i|input=s' => \$input,
'o|output=s' => \$output,
);
if ($help) {
&help();
}
if (length $input == 0 || length $output == 0) {
&usage();
}
&process();
################################################################################
## Process the Program ##
################################################################################
sub process {
# Scan the directory.
&scanDir (".");
}
sub scanDir {
my $dir = shift;
print "Descending into $dir\n" if $verbose;
opendir (DIR, $dir);
foreach my $file (sort(readdir(DIR))) {
next if $file eq '.';
next if $file eq '..';
# Is this file a directory?
if (-d "$dir/$file") {
# Are we recursing?
if ($recurse) {
&scanDir ("$dir/$file");
}
}
# Only deal with real files.
if (-f "$dir/$file") {
# Doing a string replace?
if ($replace) {
if ($file =~ /$input/i) {
my $newName = $file;
$newName =~ s/$input/$output/g;
my $confirm = 0;
if (not $force) {
print "Rename \"$dir/$file\" to \"$newName\"? [yN] ";
chomp (my $reply = <STDIN>);
if (lc($reply) eq "yes" || lc($reply) eq "y") {
$confirm = 1;
}
else {
next;
}
}
else {
$confirm = 1;
}
if ($confirm) {
if (rename("$dir/$file", "$dir/$newName")) {
print "$file => $newName\n" if $verbose;
}
else {
print "Failed to rename $file: $!";
}
}
}
next;
}
# See if this file matches our regular expression.
if ($file =~ /^$input$/i) {
# Are we allowed to modify this file?
if (-r "$dir/$file") {
# Attempt to rename it.
my @matches = ($file =~ /^$input$/i);
unshift (@matches,'');
my $newName = $output;
$newName =~ s/%(\d+?)/$matches[$1]/ig;
# Does our new name already exist?
if (-e "$dir/$newName") {
print "Warning: new filename exists for $newName\n";
# Find a unique name.
my $check = $newName;
my $i = 0;
while (-e "$dir/$check") {
$i++;
$check = "[$i] $newName";
if ($i > $limit) {
print "Error: failed to find a unique name for $newName\n";
}
}
$newName = $check;
}
# Get confirmation to rename the file.
my $confirm = 0;
if (not $force) {
print "Rename \"$dir/$file\" to \"$newName\"? [yN] ";
chomp (my $reply = <STDIN>);
if (lc($reply) eq "yes" || lc($reply) eq "y") {
# Okay.
$confirm = 1;
}
else {
# Skip this file.
next;
}
}
else {
$confirm = 1; # we used --force
}
# Attempt to rename the file.
if (rename("$dir/$file","$dir/$newName")) {
print "$file => $newName\n" if $verbose;
}
else {
print "Can't rename $file: $!\n";
}
}
else {
print "Can't rename $file: permission denied.\n";
}
}
}
}
closedir (DIR);
}
################################################################################
## Print the Usage Information ##
################################################################################
sub usage {
print "USAGE:\n"
. "\trre [-Rvf] -i expression -o expression\n"
. "See `rre --help` for full documentation.\n";
exit(0);
}
################################################################################
## Print the Full Documentation ##
################################################################################
sub help {
print qq~
NAME
rre - A rename command that supports regular expressions.
SYNOPSIS
rre [-Rrvf] [-l limit] -i inputexpr -o outputexr
DESCRIPTION
rre is a tool for renaming multiple files that match a given
regular expression and naming the new files according to a
defined pattern.
OPTIONS
--help
-h
-?
Prints this documentation.
--verbose
-v
Print verbose information about everything the program does.
--force
-f
Automatically rename files without prompting.
--recursive
--recurse
-R
Recurse into subdirectories.
--replace
-r
Do a find-and-replace instead of a regexp rename. Example:
\$ rre -r -i "_" -o " "
... to replace underscores with spaces.
--limit
-l
When trying to rename to a file that exists, numbers are
prepended until the name is unique. When "limit" is reached,
the program will quit trying and move on to the next file.
Default is 250.
--input
-i
The input regular expression to match on the files in the
directories scanned.
--output
-o
The output expression for what to name files into. Use of
variables \%1, \%2, \%3, etc. can be used here (and probably
should be). If the new file name already exists, a number will
be appended to it.
BEHAVIOR
If the target file name already exists, a number will be prepended to
the name until the file name becomes unique, or the number exceeds
the --limit, which defaults to 250. The file format of a renamed file
is "[x] filename", where x is the number which increments from 1 to
--limit.
When --force is not enabled, you will be prompted before any file
renaming operations are completed. An answer of "y" or "yes" is required
to continue; any other value (or no value) will skip the current file.
EXAMPLES
If you had a directory full of episodes for a particular TV show,
and they were all formatted with the episode numbers listed by season
and then number, such as "1x01", "1x02", "1x03", then "2x01", "2x02",
etc., and you wanted the numbers to simply be 101, 102, 103, 201, 202:
rre -i "(.+?)(\\d)x(\\d\\d)(.+?)\.avi" -o "\%1\%2\%3\%4\.avi"
If you had a directory full of MP3 files, and many of them followed
the format of "Artist - Album - Song Name.mp3", and you wanted to omit
the album name:
rre -i "(.+?) - (.+?) - (.+?)\.mp3" -o "\%1 - \%3.mp3"
AUTHOR AND VERSION
Casey Kirsle <casey at cuvou.net>
rre version $VERSION
~;
exit(0);
}