376 lines
8.3 KiB
Perl
Executable File
376 lines
8.3 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
|
|
# datename - Automatically rename a large group of files to have dates in their
|
|
# names.
|
|
#
|
|
# This script is for renaming many files (e.g. files downloaded from a digital
|
|
# camera) to have dates as their file names, e.g. from 2009-12-25_001.jpg to
|
|
# 2009-12-25_058.jpg
|
|
#
|
|
# Usage: datename [options] <files>
|
|
# See `datename -?` for more help.
|
|
#
|
|
# --Kirsle
|
|
# http://sh.kirsle.net/
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Getopt::Long;
|
|
use File::Copy;
|
|
our $version = "1.0 Feb 23 2009";
|
|
|
|
unless (@ARGV) {
|
|
print "Usage: datename [options] [files]\n"
|
|
. "Try `datename -?` for help.\n";
|
|
exit(1);
|
|
}
|
|
|
|
our %c = (
|
|
r => "\e[31m",
|
|
g => "\e[32m",
|
|
c => "\e[34m",
|
|
o => "\e[0m",
|
|
);
|
|
|
|
##############################
|
|
# Collect Options #
|
|
##############################
|
|
|
|
my @lt = localtime(time());
|
|
my $today = join("-",
|
|
sprintf("%04d", ($lt[5] + 1900)),
|
|
sprintf("%02d", ($lt[4] + 1)),
|
|
sprintf("%02d", ($lt[3])),
|
|
);
|
|
my $o = {
|
|
help => 0,
|
|
format => undef,
|
|
date => undef,
|
|
start => 1,
|
|
force => 0,
|
|
backup => "./datename-backup",
|
|
nobackup => 0,
|
|
mono => 0,
|
|
};
|
|
GetOptions (
|
|
'help|h|?' => \$o->{help},
|
|
'format|f=s' => \$o->{format},
|
|
'date|d=s' => \$o->{date},
|
|
'start|s=i' => \$o->{start},
|
|
'backup|b=s' => \$o->{backup},
|
|
'nobackup' => \$o->{nobackup},
|
|
'force' => \$o->{force},
|
|
'monotone|mono|m' => \$o->{mono},
|
|
);
|
|
if ($o->{help}) {
|
|
&help();
|
|
}
|
|
if ($o->{mono}) {
|
|
foreach my $key (keys %c) {
|
|
$c{$key} = '';
|
|
}
|
|
}
|
|
|
|
##############################
|
|
# Ask for Parameters #
|
|
##############################
|
|
$| = 1;
|
|
print "$c{r}DateName$c{o} version $c{g}$version$c{o}\n\n";
|
|
|
|
unless ($o->{nobackup}) {
|
|
print "Initializing backup directory... ";
|
|
if (!-d $o->{backup}) {
|
|
system("mkdir", "-p", $o->{backup});
|
|
if (!-d $o->{backup}) {
|
|
die "Can't create backup directory: $!";
|
|
}
|
|
}
|
|
print "Done!\n\n";
|
|
}
|
|
|
|
if (!defined $o->{format}) {
|
|
print "$c{c}1: Enter the format for the file names to follow. This should\n"
|
|
. " contain the sequences `yyyy`, `mm`, `dd`, and at least one\n"
|
|
. " `n`. For example if the format is `yyyy-mm-dd_nnn`, the\n"
|
|
. " and the date is 2009-02-23, the first file will be named\n"
|
|
. " 2009-02-23_001.jpg, the second 2009-02-23_002.jpg, and\n"
|
|
. " so-on. The default is yyyy-mm-dd_nnn. You can simply hit\n"
|
|
. " return here if you want to keep the default.$c{o}\n\n";
|
|
|
|
while (1) {
|
|
my $format = &prompt("Enter the date format, or blank for "
|
|
. "<yyyy-mm-dd_nnn>", "yyyy-mm-dd_nnn");
|
|
|
|
# Validate the format.
|
|
if ($format !~ /yyyy/ || $format !~ /mm/ || $format !~ /dd/
|
|
|| $format !~ /n+/) {
|
|
print "\n$c{r}You've entered an invalid date format. "
|
|
. "Try again.$c{o}\n\n";
|
|
}
|
|
else {
|
|
# Good.
|
|
$o->{format} = $format;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
if (!defined $o->{date}) {
|
|
print "\n$c{c}2: Enter the date that you want these files to be renamed\n"
|
|
. " after. Enter the date in the format of yyyy-mm-dd.\n"
|
|
. " Today's date is $c{g}$today$c{c}.$c{o}\n\n";
|
|
|
|
while (1) {
|
|
my $date = &prompt("Enter the date to rename the files after, "
|
|
. "or <$today>", $today);
|
|
|
|
# Validate the date.
|
|
if ($date !~ /^(\d\d\d\d)\-(\d\d)\-(\d\d)$/) {
|
|
print "\n$c{r}You've entered an invalid date. The date\n"
|
|
. "must be in yyyy-mm-dd format.$c{o}\n\n";
|
|
}
|
|
else {
|
|
# Good.
|
|
$o->{date} = $date;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
if (1) {
|
|
print "\n$c{c}3: Your files will be renamed beginning with the number "
|
|
. $c{g} . $o->{start} . "$c{c}.$c{o}\n\n";
|
|
|
|
my $answer = &prompt("Okay to begin at the number $o->{start}? "
|
|
. " [y/n] <y>",
|
|
"y",
|
|
qw(y yes n no));
|
|
if ($answer =~ /^n/i) {
|
|
while (1) {
|
|
my $start = &prompt("What number do you want to "
|
|
. "start at, or <1>", 1);
|
|
if ($start !~ /^\d+$/) {
|
|
print "\n$c{r}Invalid answer.$c{o}\n\n";
|
|
}
|
|
else {
|
|
$o->{start} = $start;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
##############################
|
|
# Summarize What's Going On #
|
|
##############################
|
|
|
|
my @files = &getFileList();
|
|
my $numFiles = scalar(@files);
|
|
my ($nss) = ($o->{format} =~ /(n+)/i);
|
|
our $ns = length $nss;
|
|
our ($year,$mon,$day) = ($o->{date} =~ /^(\d\d\d\d)\-(\d\d)\-(\d\d)$/);
|
|
if (1) {
|
|
my $backuptext = "Your files will be backed up to $o->{backup}.";
|
|
if ($o->{nobackup}) {
|
|
$backuptext = "Your files will *NOT* be backed up.";
|
|
}
|
|
my $first = &datename($o->{start});
|
|
my $last = &datename($o->{start} + $numFiles);
|
|
print "\n" . $c{c}
|
|
. ("=" x 70) . "$c{o}\n"
|
|
. "$c{g}Summary of Operations:$c{o}\n\n"
|
|
. "$c{c}Your $numFiles files are going to be renamed in the format\n"
|
|
. "'$o->{format}' using the date '$o->{date}', beginning with\n"
|
|
. "the number $o->{start}. They will be renamed from\n"
|
|
. "$first to $last.\n\n"
|
|
. "$backuptext$c{o}\n\n";
|
|
|
|
my $proceed = &prompt("Okay to proceed? [y/n] <n>", "n",
|
|
qw(y yes n no));
|
|
unless ($proceed =~ /^y/i) {
|
|
print "\nAborting procedure!\n";
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
##############################
|
|
# Main Operation #
|
|
##############################
|
|
|
|
my $int = $o->{start};
|
|
foreach my $file (@files) {
|
|
next unless -f $file;
|
|
my ($ext) = ($file =~ /\.([A-Za-z0-9]+?)$/i);
|
|
$ext = "jpg" unless defined $ext;
|
|
print "$c{c}Looking at file $file$c{o}\n";
|
|
unless ($o->{nobackup}) {
|
|
my $backup = $file;
|
|
my $bi = 1;
|
|
while (-f "$o->{backup}/$backup") {
|
|
$backup = "[$bi] $file";
|
|
$bi++;
|
|
}
|
|
print " Backing it up as $o->{backup}/$backup... ";
|
|
copy ($file, "$o->{backup}/$backup");
|
|
if (-f "$o->{backup}/$backup") {
|
|
print "Done!\n";
|
|
}
|
|
else {
|
|
die "$c{r}Error: couldn't back it up: $!$c{o}";
|
|
}
|
|
}
|
|
|
|
my $newName = &datename($int) . "." . lc($ext);
|
|
$int++;
|
|
print " Renaming file to $newName"
|
|
. ($o->{force} ? " (forced)" : "")
|
|
. "... ";
|
|
if (-f $newName && !$o->{force}) {
|
|
print "Warning: File already exists!$c{r}\n";
|
|
my $continue = &prompt(
|
|
" The file $newName already exists. Overwrite? "
|
|
. "[y/n] <n>", "n", qw(y yes n no));
|
|
|
|
if ($continue !~ /^y/i) {
|
|
print " Skipping rename of $file!$c{o}\n";
|
|
next;
|
|
}
|
|
|
|
print " Renaming file to $newName (forced)... $c{o}";
|
|
}
|
|
|
|
# Rename it.
|
|
rename ($file, $newName);
|
|
print "$c{g}Done!$c{o}\n";
|
|
}
|
|
|
|
print "\n"
|
|
. "$c{g}Procedure completed. Backups were saved to $o->{backup}.$c{o}\n";
|
|
exit(0);
|
|
|
|
sub datename {
|
|
my $i = shift;
|
|
|
|
my $format = $o->{format};
|
|
$format =~ s/yyyy/$year/ig;
|
|
$format =~ s/mm/$mon/ig;
|
|
$format =~ s/dd/$day/ig;
|
|
my $sprint = sprintf("%0${ns}d", $i);
|
|
$format =~ s/n+/$sprint/ig;
|
|
return $format;
|
|
}
|
|
|
|
sub getFileList {
|
|
if (@ARGV) {
|
|
return (@ARGV);
|
|
}
|
|
my @return = ();
|
|
opendir (DIR, ".");
|
|
foreach my $f (sort(grep(/^\./, readdir(DIR)))) {
|
|
if (-f $f) {
|
|
push (@return, $f);
|
|
}
|
|
}
|
|
closedir (DIR);
|
|
return (@return);
|
|
}
|
|
|
|
sub prompt {
|
|
my $question = shift;
|
|
my $default = shift;
|
|
my @accept = ();
|
|
|
|
my $asking = 1;
|
|
while ($asking) {
|
|
print "$question ";
|
|
chomp (my $answer = <STDIN>);
|
|
|
|
if (defined $answer && length $answer) {
|
|
if (@accept) {
|
|
foreach my $a (@accept) {
|
|
if ($answer eq $a) {
|
|
return $a;
|
|
}
|
|
}
|
|
print "Invalid answer.\n";
|
|
}
|
|
else {
|
|
return $answer;
|
|
}
|
|
}
|
|
else {
|
|
if (@accept) {
|
|
print "INvalid answer.\n";
|
|
}
|
|
else {
|
|
return $default;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sub help {
|
|
print <<EOF;
|
|
NAME
|
|
|
|
datename - Massively rename multiple files
|
|
|
|
USAGE
|
|
|
|
datename [options] <files>
|
|
|
|
OPTIONS
|
|
|
|
The following options can be provided at the command line, or will be
|
|
prompted for during operation.
|
|
|
|
--format, -f <format>
|
|
|
|
Provide the date format. Should contain yyyy, mm, dd, and a
|
|
sequence of at least one n. Ex: yyyy-mm-dd_nnn
|
|
|
|
--date, -d <date>
|
|
|
|
Provide the date. Should be in yyyy-mm-dd format, e.g.
|
|
2009-02-23
|
|
|
|
--start, -s <number>
|
|
|
|
Enter the iteration number to begin renaming files at. By
|
|
default it is 1.
|
|
|
|
The following options will modify the default behavior of the program:
|
|
|
|
--backup, -b <directory>
|
|
|
|
Specify the directory you want the files backed up into.
|
|
Default is ./datename-backup
|
|
This folder will try to be created if it doesn't exist.
|
|
|
|
--nobackup
|
|
|
|
Do not back up files (I don't recommend this option).
|
|
|
|
--force
|
|
|
|
Force rename all files (do not prompt the user if the file
|
|
already exists).
|
|
|
|
EXAMPLES
|
|
|
|
; Specify all the prompt questions on the command line and rename
|
|
; JPG and PNG images only.
|
|
datename -f "yyyy-mm-dd_nnn" -d "2009-02-23" -s 100 *.jpg *.png
|
|
|
|
; Rename JPG, BMP, and GIF, will be prompted for the other options
|
|
datename *.jpg *.bmp *.gif
|
|
|
|
; Rename everything
|
|
datename *
|
|
|
|
AUTHOR
|
|
|
|
Casey Kirsle
|
|
http://www.kirsle.net/
|
|
EOF
|
|
exit(1);
|
|
}
|