2

Situation:

Numerous sub-folders with random folder names containing several files with random names. Some I want to retain, others can be deleted.

Goal:

Move the files with extensions: *.exe *.pdf *.avi or other specified extentions out of the subfolders and into a common separate folder without recreating the previous folder structure. So that I have one folder with just the files I want, leaving behind any other file types. Then log the subfolder directory names (results-log.log) and delete the subfolders and everything left in them.

Example; starting:

  • parent1
    • sub1
      • random1.exe
      • random2.pdf
      • random3.txt
    • sub2
      • random4.exe
      • random5.avi
      • random6.log
      • random7.jpg

End result:

  • parent2
    • results-log.log
    • random1.exe
    • random2.pdf
    • random4.exe
    • random5.avi

So I've searched around for other answers and it looks like I need some sort of FOR loop, but I don't understand enough of how that works with parameters to do what I need. Moving pdf files to parent folder from subfolder with variable names is one example I looked at, and I looked over the suggested reading, but I totally don't get how the parameters and variables work. Especially where I need to cover several file types.

So far I'm looking at something like this:

@ECHO OFF
SETLOCAL EnableExtensions
set "_parent=c:\logs\cache\"
set "_dest=c:\archive\"
for /D /r %%G in ("%_parent%\*") do (
  if exist "%%~G\*.pdf" (
    echo move /B "%%~G\*.pdf" "%_dest%\"
  ) else (
    echo nothing to copy "%%~G\*.pdf" "%_parent%\"
  )
)
  • Line 3 I believe that sets "c:\logs\cache\" as the parent folder, so in my example about that would equal "parent1"
  • Line 4 should set the destination for example folder "parent2" as "c:\archive"
  • Line 5 is %%G correct? Does it matter what the letter is?
  • Line 6 how do I specify the other file extensions I want to look for?
  • Line 7 do I want to use move or something else, and what's the /B parameter? /y is the only one I know of for move.

Hopefully that's enough info, can edit as needed for more info.

1 Answers1

3

All you need to do is make multiple if statements I would think. So inside your loop it would look like this:

IF exist "%%G\*.pdf" (
    move /Y "%%G\*.pdf" "%_dest%\"
    echo %%G>>"%_dest%\results-log.log
)

IF exist "%%G\*.exe" (
    move /Y "%%G\*.exe" "%_dest%\"
    echo %%G>>"%_dest%\results-log.log
)
IF exist "%%G\*.avi" (
    move /Y "%%G\*.avi" "%_dest%\"
    echo %%G>>"%_dest%\results-log.log
)

If you want to keep the message saying nothing to move, you can always set some variable if it gets inside one of those IF statements and check that it's set.

I'm not sure what /B is, that doesn't look right to me. I think you're right with /y.

The G can be any character, but it can't be more than one character. G is what is generally used.

I would suggest looking into powershell scripts for things like this. In my opinion it's cleaner and more simple to do things like this with less lines of code. There might be a command to move all files with multiple extensions at once, but from what I understand that syntax isn't usually available for move in most versions of DOS.

EDIT:

I've tested this locally and it seems to work for what you are doing. You'll need to tweak it for your specific case.

@ECHO OFF
SETLOCAL EnableExtensions enabledelayedexpansion
set _parent=c:\logs\cache\
set _dest=c:\archive\
set found=0

for /R  %_parent% %%G in (.) do (
    set found=0
    IF exist "%%G\*.pdf" (
        move /Y "%%G\*.pdf" "%_dest%\"
        set found=1
    )
    IF exist "%%G\*.exe" (
        move /Y "%%G\*.exe" "%_dest%\"
        set found=1
    )
    IF exist "%%G\*.avi" (
        move /Y "%%G\*.avi" "%_dest%\"
        set found=1
    )

    IF !found!==1 (
        rd /s /q "%%G"
        echo %%G>>"%_dest%\results-log.log"
    )
)

endlocal

Using the /D option in the for loop attaches the current directory where you're running the script to the %%G variable which I don't think is what you want. The way I've written it above basically says recurse all folders in the parent directory and set %%G to that location (.).

You have to add the enabledelayedexpansion as well so that you can use the found variable in different blocks, then you have to call !found! instead of %found% to use it. Just a weird quirk of batch scripting.

If all this syntax seems really weird to you, you're not alone. You just have to research away and just do your own testing to see what happens until you get it to do what you want. Hopefully when you jump into powershell you'll find debugging using powershell ISE and the syntax used much more simple.

  • I haven't tested all of this syntax, but it should at least get you close to what you need. I would put all the conditions in one if statement, but I think you can only do and and not or for if conditions. One more reason to use powershell :) – mrfreester Oct 19 '15 at 22:18
  • Okay, so to make sure I'm understanding this correctly. Your code replaces my IF statement, but I still keep the first 4 lines as they are, correct? Then what do I do about the else portion? Add it after all of my IF statements with an echo to the log file?

    p.s. I'm open to doing this with PowerShell instead, but I know even less about using PS, it's on my list of things I need to learn soon.

    – WraythOsu Oct 20 '15 at 15:07
  • I added the entire example of using a variable to see if anything was moved. You'll use that instead of an else statement since batch doesn't support else if's – mrfreester Oct 20 '15 at 17:18
  • It's working!!! (imagine young Anakin in eps 1) :-) So, last bit is to delete the old subfolders after we move the files. so do I add rd /s /q %%G between the move line and the set line in each statement? My only concern here is that I don't want to delete a folder that might contain a file type I haven't factored in the script. So say a folder shows up as a .msi instead of .exe, I want that folder to be left alone for now. So I only want it to delete a folder if a file has been moved out. – WraythOsu Oct 20 '15 at 19:50
  • I would probably put the rd /q %%G line the last if block where you write to the log file since you should get into that only if you deleted something in the previous if blocks. I would probably leave out the /s option as I think that will delete the directory even if there are still files in it. If you leave out /s then I'm pretty sure it'll do what you want, which is delete the folder only if it's empty. – mrfreester Oct 20 '15 at 22:43
  • This answer is something you could run after the entire for loop to delete all the empty folders. You just need to replace the directory they specify with your _parent variable: http://superuser.com/a/39679/352083 – mrfreester Oct 20 '15 at 22:55
  • thank you for sticking with me on this! So actually the sub-directories won't be empty, they will still have some small extra files I don't care about and want deleted, so I do want to use the /s. But I don't want to delete everything from the _parent on down. In case a new file type comes in that doesn't get moved, I want that folder to stay in place so I can evaluate it. So I just want to delete the folders where I've moved a file from. – WraythOsu Oct 21 '15 at 13:22
  • Okay, I inserted the rd /s /q %%G and it did what I wanted. Only problem was it didn't delete a directory with a space in it. So can I just put " " around the %%G like this: rd /s /q "%%G"? I know that quotes can do weird things if not done right. So all I need now is the correct formatting for that line and this is answered. woohoo! – WraythOsu Oct 21 '15 at 15:33
  • I see. There is a possibility that using /s might delete some folders before you move the files depending on how the loop iterates through folders. Example, if you have f1/f2 both with files in them, and the loop goes through f1 first, if you delete that folder you might accidentally remove everything in f2. You might want to throw in some echo statements to see the order. If the loop always goes through the top folder first consider yourself lucky, and all you'll need to do is use rd in that last if statement. If not so lucky, you'll have to work through some more logic. – mrfreester Oct 21 '15 at 15:35
  • Okay, I see what your saying, I don't think I will have sub-subfolders so I'm not going to worry about that, so just need the RD command to handle folder names with spaces and we are all set. – WraythOsu Oct 21 '15 at 15:39
  • Yep, that should be all you need, just put the quotes around it. If that doesn't work for some reason let me know. – mrfreester Oct 21 '15 at 15:49
  • That worked, I've edited the code in your answer and marking this as answered. Thank you very much for all your help @mrfreester! – WraythOsu Oct 21 '15 at 15:54