3

I have a directory with many sub-directories that contain thousands of jpgs. What I want to do is create a batch script that will go through all of the sub-directories and delete every 2nd image i.e. keep the first, third, fifth image but delete the second, fourth, and six image etc per directory (ordered by filename).

I tried with the following but my knowledge of batch scripting is poor, and the syntax is clearly incorrect.

@echo off
set z = 0
for /f %%a in ('dir/b *.jpg')
do (
  set z = z + 1
  if z == 2 del %%a
)
tshepang
  • 12,111
  • 21
  • 91
  • 136

2 Answers2

5
  • The DO must be on the same line as FOR.

  • You must use SET /A if you want to do math

  • Your logic is wrong - Currently it will only delete the 2nd file, not every other one. You should take the mod 2 value (remainder devided by 2) and delete if the result is 0.

  • You must use %z% if you want to see the current value (except within a SET /A statement). But that will not work inside a code block that just set the value. In that case you need to enable delayed expansion and use !z! instead.

  • Expanding a FOR variable that contains ! (valid in file names) while delayed expansion is enabled will corrupt the value. So delayed expansion must be toggled on and off

  • You say you want to recurse sub-directories, but your code only looks at one folder.

  • Spaces are significant in the SET statement. Your code defines a variable z with a space at the end of the name. Not what you want.

Here is a debugged version:

@echo off
setlocal
for /r %%D in (.) do (
  set "z=0"
  for /f %%F in ('dir /b "%%D\*.jpg"') do (
    set /a "z+=1, r=z%%2"
    setlocal enableDelayedExpansion
    if !r! equ 0 del "%%D\%%F"
    endlocal
  )
)

There are ways to solve this without delayed expansion. One is to simply alternate between defining and undefining a variable.

@echo off
setlocal
for /r %%D in (.) do (
  set "del="
  for /f %%F in ('dir /b "%%D\*.jpg"') do if defined del (
    del "%%D\%%F"
    set "del="
  ) else set "del=1"
)

Another is to intentionally divide by 0 when you want to delete, and delete only when there is an error. Error messages are hidden by 2>nul, and the || operator conditionally executes the following command only if the prior command failed.

@echo off
setlocal
for /r %%D in (.) do (
  set "z=0"
  for /f %%F in ('dir /b "%%D\*.jpg"') do 2>nul set /a "z+=1, 1/(z%%2)" || del "%%D\%%F"
)
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • With dir/b I think it will only process current dir. If I use dir/b/s and run in root will it delete 2nd etc image from all subfolders as well. – user2832776 Sep 30 '13 at 22:26
  • @user2832776 - Yep. I allowed myself to be influenced by your original code. All fixed now. The FOR /R walks the directory tree, and the delete "flag" is reset for each directory. – dbenham Sep 30 '13 at 22:38
  • @LS_dev - No, SET /A is able to read the value of a variable without expansion - a very convenient feature. – dbenham Oct 01 '13 at 11:29
  • @LS_dev - Oops, you are correct on that one. All fixed. Thanks. – dbenham Oct 01 '13 at 12:54
  • This worked for me, but filenames with spaces in them don't get deleted. I remove the spaces using this script. Can they be merged somehow? https://stackoverflow.com/questions/11270453/how-to-remove-spaces-from-file-names-in-bulk – ICTAddict May 25 '18 at 12:17
  • The first script works well but I would like to modify it so it only deletes the files in the current directory (otherwise could do a lot of damage if accidentally executed at the root!). What items must be removed to stop recursive deletion? – Markm0705 Mar 31 '21 at 09:45
1

try this and remove the echo if the output looks good:

@echo off &setlocal
for /f "tokens=1*delims=:" %%a in ('dir /b /s /a-d *.jpg^|findstr /n $') do (
    echo %%a|findstr "[02468]$" >nul && echo del "%%~b"
)
Endoro
  • 37,015
  • 8
  • 50
  • 63
  • +1 Nice script, but will not reset counter for each subdirectory. – LS_ᴅᴇᴠ Oct 01 '13 at 09:49
  • @LS_dev Obviously not. It was not required. It also makes no sense, imo. :) – Endoro Oct 01 '13 at 10:49
  • This will give the wrong result if there are 20 or more files. BTW - I think the entire task makes no sense. But there is a significant difference if count is reset for each folder. If not reset, then a folder starting with 1 file may end up with no files, so it cannot be differentiated from a folder starting with no files. If reset each folder, then every folder that started with at least one file will end up with at least one file. The down side is if every folder has exactly one file, then no file is deleted :) – dbenham Oct 01 '13 at 12:22