#!/usr/bin/perl
# open the directory in the first arg (defaults to
# .) and get a sorted list of all files ending in
# .dpx into array @files
opendir(my $dir, shift // '.');
my @files = sort grep { /^Frame .*\.dpx$/ } readdir($dir);
close($dir);
# get the numeric value of the first and last
# element of the array
my ($first) = split /\./, $files[0];
my ($last) = split /\./, $files[-1];
#print "$first\n$last\n";
# find and print any missing filenames
foreach my $i ($first..$last) {
my $f = sprintf("%08i.dpx",$i);
print "File '$f' is missing\n" unless -e $f
};
Save that as, say, find-missing.pl
, and make it executable with chmod +x find-missing.pl
.
First, I need to randomly create a bunch of matching files for a test run (ten or fewer files is enough for this test):
$ for i in {0..9} ; do
[ "$RANDOM" -gt 16384 ] && printf "%08i.dpx\0" "$i" ;
done | xargs -0r touch
$ ls -l *.dpx
-rw-r--r-- 1 cas cas 0 Feb 24 13:30 00000000.dpx
-rw-r--r-- 1 cas cas 0 Feb 24 13:30 00000001.dpx
-rw-r--r-- 1 cas cas 0 Feb 24 13:30 00000003.dpx
-rw-r--r-- 1 cas cas 0 Feb 24 13:30 00000005.dpx
-rw-r--r-- 1 cas cas 0 Feb 24 13:30 00000006.dpx
-rw-r--r-- 1 cas cas 0 Feb 24 13:30 00000007.dpx
-rw-r--r-- 1 cas cas 0 Feb 24 13:30 00000008.dpx
In bash, $RANDOM
gives a random number between 0 and 32767...so the for
loop has a roughly 50% chance of creating any file. In this run, you can see that all but 00000002.dpx, 00000004.dpx, and 00000009.dpx were created.
and then run the perl script:
$ ./find-missing.pl .
File '00000002.dpx' is missing
File '00000004.dpx' is missing
NOTE: It doesn't mention 00000009.dpx
because that is beyond the highest-numbered file found. If you want it to do that, then either hard-code $last
to a suitable value, or take it from a command-line argument.
Second version, for filenames beginning with Frame
. Also allows configuration by variables at the top of the script - BTW, there's no reason why these couldn't be taken from the command line (in array @ARGV
, or with a module like Getopt::Std or Getopt::Long):
#!/usr/bin/perl
# Configuration variables
my $digits = 7;
my $prefix = 'Frame ';
my $suffix = '.dpx';
# Format string for printf
my $fmt = "$prefix%0${digits}i$suffix";
# Open the directory in the first arg (defaults to
# the current dir, ".") and get a sorted list of all
# files starting with $prefix and ending in $suffix
# into array @files
opendir(my $dir, shift // '.');
my @files = sort grep { /^$prefix.*$suffix$/ } readdir($dir);
close($dir);
# Get the numeric value of the first and last
# element of the array by removing the filename
# prefix (e.g. "Frame ") and suffix (e.g. ".dpx"):
my ($first, $last);
($first = $files[0]) =~ s/^$prefix|$suffix$//g;
($last = $files[-1]) =~ s/^$prefix|$suffix$//g;
#print "$first\n$last\n";
# find and print any missing filenames
foreach my $i ($first..$last) {
my $f = sprintf($fmt, $i);
print "File '$f' is missing\n" unless -e $f
};
BTW, ($first = $files[0]) =~ s/^$prefix|$suffix$//g;
is a common perl idiom for assigning a value to a variable and modifying it with a substitution s///
operation. It's equivalent to:
$first = $files[0];
$first =~ s/^$prefix|$suffix$//g;
To print the total number of files (and the number of missing files too), change the final block of code (everything from # find and print any missing filenames
onwards) in either version above to:
# find and print any missing filenames
my $missing = 0;
foreach my $i ($first..$last) {
my $f = sprintf($fmt, $i);
if (! -e $f) {
print "File '$f' is missing\n";
$missing++;
};
};
printf "\nTotal Number of files: %i\n", scalar @files;
printf "Number of missing files: %i\n", $missing;
That will produce output like this:
$ ./find-missing2.pl
File 'Frame 00000002.dpx' is missing
File 'Frame 00000003.dpx' is missing
Total Number of files: 7
Number of missing files: 2