Iterating through folders and files in batch file?

Will Marcouiller picture Will Marcouiller · Jun 8, 2010 · Viewed 22.6k times · Source

Here's my situation. A project has as objective to migrate some attachments to another system.

These attachments will be located to a parent folder, let's say "Folder 0" (see this question's diagram for better understanding), and they will be zipped/compressed.

I want my batch script to be called like so:

BatchScript.bat "c:\temp\usd\Folder 0"

I'm using 7za.exe as the command line extraction tool.

What I want my batch script to do is to iterate through the "Folder 0"'s subfolders, and extract all of the containing ZIP files into their respective folder.

It is obligatory that the files extracted are in the same folder as their respective ZIP files. So, files contained in "File 1.zip" are needed in "Folder 1" and so forth.

I have read about the FOR...DO command on Windows XP Professional Product Documentation - Using Batch Files.

Here's my script:

@ECHO OFF

FOR /D %folder IN (%%rootFolderCmdLnParam) DO 
    FOR %zippedFile IN (*.zip) DO 7za.exe e %zippedFile

I guess that I would also need to change the actual directory before calling 7za.exe e %zippedFile for file extraction, but I can't figure out how in this batch file (through I know how in command line, and even if I know it is the same instruction "cd").

EDIT #1

I have already received some tips on ServerFault to the same question. Please see the answers at this link.

However, it extracted from the root (C:), and not from the given in parameter folder.

Anyone has an idea?

EDIT #2

It seems that batch script doesn't handle folder and file names containing a space character adequately. Can anyone confirm what I think?

EDIT #3

I need it to be fully recursive, since I don't know the directory structure against which this will be used.

EDIT #4.a

With @aphoria's solution, I'm almost there! The only problem is that it takes let's say File5.zip, retrieve the filename only to get File5, creates a subfolder File5 and extract the File5.zip to File5 subfolder, then, it wants to create a File5 subfolder in Folder 1, where it should instead want to create File1 subfolder, to stick with my example.

EDIT #4.b

As required, here's the code as it currently look:

@echo off

setlocal enableextensions enabledelayedexpansion

rem
rem Display instructions when no parameter is given.
rem
if "%1" equ "" (
    echo Syntaxe : od.bat ^<directory mask>^
    echo Exemple : od.bat *
    goto :Eof
)

rem
rem Setting the PATH environment variable for this batch file for accessing 7za.exe.
rem
path=c:\temp;%PATH%

rem
rem Removing quotes from the given command line parameter path.
rem
set root=%1
set root=%root:~%1
set root=%root:~0,-1%

rem Searching directory structure from root for subfolders and zipfiles, then extracting the zipfiles into a subfolder of the same name as the zipfile.
for /F "delims==" %%d in ('dir /ogne /ad /b /s %root%') do (
    echo Traitement du dossier : "%%d"

    for /F "delims==" %%f in ('dir /b "%%d\*.zip"') do (
        rem Getting filename without extension.
        set subfolder=~n%f
        mkdir "%%d\%subfolder%"
        rem Extracting zipfile content to the newly created folder.
        7za.exe e "%%d\%%f" -o"%%d\%subfolder%"
    )
)

:Eof

endlocal

Ideas anyone?

My guess is that it digs one directory hierarchy at a time. Here's the deal. Consider we have a Folder A in Folder 1 (Folder 1\Folder A), then, it searches from Folder 1 through Folder 5, and comes back to Folder 1\Folder A, where the %subfolder% variable sticks with its last value.

Anyone's help is gratefully appreciated.

Answer

aphoria picture aphoria · Jun 9, 2010

I'm not very familiar with the 7zip command-line options, so you will need to figure out the exact command for that, but the script below will take a fully specified path (spaces allowed) and print out the the folder name and .zip files contained within it.

@ECHO OFF

REM
REM Remove the double quotes from the front and end of the root path
REM
SET ROOT=%1
SET ROOT=%ROOT:~1%
SET ROOT=%ROOT:~0,-1%
ECHO %ROOT%

FOR /F "DELIMS==" %%d in ('DIR "%ROOT%" /AD /B') DO ( 
  ECHO %%d
  FOR /F "DELIMS==" %%f in ('DIR "%ROOT%\%%d\*.zip" /B') DO (
    ECHO   %%f
  )
)  


Run it like this:

MyScript.CMD "c:\temp\usd\Folder 0"

You should get output similar to this:

Folder A
  File 1.zip
  File 2.zip
Folder B
  File 1.zip
  File 2.zip  


UPDATE

The code below will extract Folder A\File 1.zip to a new folder Folder A\File 1.

A few things to keep in mind:

  1. In the first FOR loop, you need to have %ROOT% enclosed in double quotes to handle folders with spaces in the name.
  2. Since you're SETting a variable inside the second FOR, you need to put SETLOCAL ENABLEDELAYEDEXPANSION at the beginning. Then, reference the variable using ! (for example, !subfolder!) to force expansion at runtime.
  3. This line of your code set subfolder=~n%f should be this set subfolder=%%~nf
  4. I put ECHO in front of the MKDIR and 7za.exe commands to test. Once you are sure it is doing what you want, remove the ECHO statement.

Here is the code:

@ECHO OFF

SETLOCAL ENABLEDELAYEDEXPANSION

REM
REM Remove the double quotes from the front and end of the root path
REM
SET ROOT=%1
SET ROOT=%ROOT:~1%
SET ROOT=%ROOT:~0,-1%
ECHO %ROOT%

REM Searching directory structure from root for subfolders and zipfiles,
REM then extracting the zipfiles into a subfolder of the same name as the zipfile.

FOR /F "delims==" %%d IN ('dir /ogne /ad /b /s "%ROOT%"') DO (
    ECHO Traitement du dossier : "%%d"

    FOR /F "delims==" %%f IN ('dir /b "%%d\*.zip"') DO (
        REM Getting filename without extension.
        SET subfolder=%%~nf
        ECHO mkdir "%%d\!subfolder!"
        REM Extracting zipfile content to the newly created folder.
        ECHO 7za.exe e "%%d\%%f" -o"%%d\!subfolder!"
    )
)

ENDLOCAL