Yesterday, I saw a tweet by a veteran admin complaining that the candidates he interviews these days can’t code up simple scripts. Intrigued, I asked him what he considers simple, to which he replied that he asked a candidate to rename a million files on JFS2 on a SAN.
Today, after work, I thought I’ll see what I would do if I were asked the question. I came up with 3 quick ways to do this, but since I don’t have a san running JFS2, I tested this on my mac.
I assumed that we are changing the extension of the files in the directory. The real use case may differ, but the approach will be the same. I didn’t create a million files either. Just 100K.
moosha:testdata$ time for i in {1..100000} ; do touch $i.abc ; done
real 9m40.692s
user 0m41.439s
sys 8m56.233s
Method 1:
ls * | awk -F. '{ print "mv "$0" "$1".wmv" }' | sh
As soon as I wrote this down I knew that ls would break. So I modified it –
echo * | awk -F. '{ print "mv "$0" "$1".wmv" }' | sh
Turns out that mv breaks as well. Ok, no worries.
Method 2:
This method I knew would work.
for i in `echo *` ; do mv $i "${i%.*}".wmv ; done
It did, but
moosha:testdata$ time for i in `echo *` ; do mv $i "${i%.*}".wmv ; done
real 20m3.923s
user 0m48.597s
sys 19m15.824s
So it took 20 min. Hmm. Surely, we can do better. Ok, perl it is.
Method 3:
I hacked an old perl script (because I was lazy to start from scratch)
#!/usr/bin/perl
# Program that renames files in a directory.
use Cwd;
use File::Copy;
my $startdir = cwd;
my $rendir = $ARGV[0];
my $newext = $ARGV[1];
if (($rendir eq '') || ($newext eq '')) {
print "You need to specify a directory.\n";
print "Usage : perl file_rename.pl \n";
exit 0;
}
print "Going to rename files in $rendir. Are you REALLY sure? (Y/N) : ";
my $a = ;
chop $a;
print "\n";
while ($a eq "Y") {
chdir $rendir or die "Can't get into the directory : $rendir";
opendir my $DIR,'.' or die "Can't open the directory : $rendir";;
while (my $n = readdir $DIR) {
if ($n ne '.' && $n ne '..') { #Ignoring current and parent directories
#mv $n "${n%.*}".wmv
my ($head) = $n =~ /(.+?)(\.[^.]*$|$)/;
move ($n,"$head.$newext");
}
}
closedir $DIR;
chdir $startdir or die "Can't get back to starting directory : $startdir\n";
$a = 'N' ;
}
And running that,
moosha:code hriday$ time ./perl/file_rename.pl testdata wmv
Going to rename files in testdata. Are you REALLY sure? (Y/N) : Y
real 14m7.924s
user 0m5.918s
sys 13m52.067s
Cool. I shaved 7 minutes in perl. I’ll use this method.
Experiment over. Next week, I’ll set up a SAN with JFS2 and test again. In the next few weeks, I am going to install 4-5 filesystems on that SAN and benchmark them. One of the tests has got to be renaming files.
H.