Well, it turns out that after creating a PowerShell script to list deleted files (part 1) and another PowerShell script to monitor for deleted, renamed or moved files (part 2), I've decided to revert to a simple, batch file instead because running a batch file is so much easier than PowerShell!

As you know, my requirement is simply to list missing files in a sequentially named list of images (off my digital camera) i.e. given files DSCF0081.JPG, DSCF0083.JPG, DSCF0085.JPG, DSCF0086.JPG, then DSCF0082.JPG and DSCF0084.JPG must have been deleted. In the case the first and/or last file have also been deleted, then a input parameters should define the lowest and highest range instead.

So, here is find_deleted.cmd, which can either be run with:

  • no inputs - as in the scenario above,
  • one input - to define the lower bound,
  • two inputs - to define the lower bound and higher bound.

It's important to note that my assumption is a fixed file name convention of DSCFxxxx.JPG, where xxxx is between 0000 and 9999 exactly. This is very important, as I use 2 little tricks to convert strings to/from numbers:

  • To convert "0001" to a number involves concatenating "1000" and getting the modulus (remainder after dividing) of 1000, i.e. 1000001 % 1000 = 1
  • And to convert 1 back to "0001", I check if the value is less than 10, and if so, pad it with "000".

Another interesting trick to get the first / last file and just pulling out the numeric part is using for /f "delims=DSCF." %%f in ('dir *.jpg /b/on'). The effect of the delims keyword is to skip over D, S, C, or F and assign anything after the . to a different variable, leaving %%f as what's in between, i.e. the 4 digits. The 'dir *.jpg /b/on' gets the directory list sorted by name, while 'dir *.jpg /b/o-n' sorts in reverse order!

@echo off
setlocal EnableDelayedExpansion
if "%1"=="" ( call :find_first_file ) else ( set /a first=%1 )
if %first% leq 0 goto find_no_files
if "%2"=="" ( call :find_last_file ) else ( set /a last=%2 )
if %last% leq %first% goto find_no_files
echo Finding deleted photos between %first% and %last%
for /l %%i in (%first%,1,%last%) do (
 if %%i lss 10000 set x=%%i
 if %%i lss 1000 set x=0%%i
 if %%i lss 100 set x=00%%i
 if %%i lss 10 set x=000%%i
 if not exist "DSCF!x!.jpg" echo Deleted DSCF!x!.jpg
)
echo All done!
exit /b0
:find_first_file
set /a first=-1
for /f "delims=DSCF." %%f in ('dir *.jpg /b/on') do (
 set /a first=10000%%f %% 10000
 goto :eof
)
goto :eof
:find_last_file
set /a last=-1
for /f "delims=DSCF." %%f in ('dir *.jpg /b/o-n') do (
 set /a last=10000%%f %% 10000
 goto :eof
)
goto :eof
:find_no_files
echo No DSCFxxxx.JPG photos found or invalid input!
exit /b1

The script I use doesn't only list the missing files, but rather goes ahead and deletes files of the same name from my SD card. You can imagine I'd need another input parameter to specify the folder where the files reside. However, I won't share that - anything so dangerous requires too many disclaimers.