Iterating through folders and files in batch file? - batch-file

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.

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:
In the first FOR loop, you need to have %ROOT% enclosed in double quotes to handle folders with spaces in the name.
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.
This line of your code set subfolder=~n%f should be this set subfolder=%%~nf
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

Related

Copy one file to one folder at a time where there are 100 files and 100 folders to copy using Batch file

I have two folders CopyFrom and CopyTo where CopyFrom has 100 text files named as 1.txt…100.txt and in CopyTo folder I have 100 folders as F1…F100. Now, I want to copy one file from CopyFrom folder to one folder in CopyTo so that F1 will contain 1.txt, F2 will contain 2.txt,…, F100 will contain 100.txt file.
I know to copy all folders I can use something like For /d %%a in (C:\Users\me\Desktop\ShortCuts\*) do xcopy "C:\Users\me\Desktop\Time.xls" "%%a", but I could not find a way to copy different files to different folders.
I can echo all the files (For %%a in (C:\Users\me\Desktop\ShortCuts\*) Echo "%%a") in the CopyFrom folder and also can Echo all the folders in CopyTo folder but could not figure out to working with both to get what I am looking for.
#echo off
setlocal enableextensions disabledelayedexpansion
rem Configure paths
set "copyFrom=c:\somewhere"
set "copyTo=c:\anotherPlace"
rem Generate two lists, one with files and one with folders
dir /b /a-d "%copyFrom%\*" > "%temp%\copyFromFiles.txt"
dir /b /ad "%copyTo%\*" > "%temp%\copyToFolders.txt"
rem Assign each list as input to two streams and start processing
9< "%temp%\copyFromFiles.txt" 8< "%temp%\copyToFolders.txt" (
call :matchFromWithTo
)
rem Remove generated lists
del "%temp%\copyFromFiles.txt"
del "%temp%\copyToFolders.txt"
rem End
goto :eof
:matchFromWithTo
rem Read file from stream 9 and leave if nothing read
<&9 set /p "file=" || goto :eof
rem Read folder from stream 8 and leave if nothing read
<&8 set /p "folder=" || goto :eof
rem Do the copy (debug: we will only echo the command)
echo copy "%copyFrom%\%file%" "%copyTo%\%folder%"
rem Keep reading until all files or folders are processed
goto :matchFromWithTo
Supposing the source location contains the files 1.txt to 100.txt only and the target location already contains all the F1 to F100 directories, the following code snippet might work for you:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "Pattern=*.txt"
set "CopyFrom=."
set "CopyTo=D:\Target"
for %%F in ("%CopyFrom%\%Pattern%") do (
ECHO copy "%%~F" "%CopyTo%\F%%~nF\"
)
endlocal
exit /B
There is no enumeration of the target location done, the copy destination is simply derived from the source file name.
After having tested the script, remove the upper-case ECHO command to actually copy files!

Batch Finding and displaying duplicate strings in file names

I have a question. Is it possibile in batch language to search in folder a part of name that is same like another file and display it.For example i got folder with files :
ggggggsss.mp3
ddddddeee.mp3
ddddddff.mp3
ssssssddd.mp3
aaaaasssss.mp3
11111ssdas.mp3
11111dddd.mp3
...
I need to display in cmd only names of files
ddddddeee
ddddddff
and
11111ssdas
11111dddddd
Because the first six letter are the same. Could someone help me with this problem?
Save this script to test.bat and run from open Cmd Prompt. Replace dir value with path to your folder with .mp3 files:
#echo off
setlocal enabledelayedexpansion
set "dir=%userprofile%\music"
set "pattern1=dddddd" & set "pattern2=11111"
pushd "%dir%"
FOR %%G IN (*.mp3) DO ( set song=%%G
if "!song:~0,6!"=="%pattern1%" echo %%G)
echo/
FOR %%G IN (*.mp3) DO ( set song=%%G
if "!song:~0,5!"=="%pattern2%" echo %%G)
popd
exit /b
See also Extract Substrings.

Batch file to loop through subfolder and use subfolder name as variable

this is my first post as im having a little trouble with a batch file to loop through subfolders and use the subfolder name as a variable in a command. I have managed to get the code well enough advanced and it runs, but continually repeats running with the last folder name in the main directory. It doesn't find and cycle through the other subfolders.
SETLOCAL EnableDelayedExpansion
SET MYPATH=H:\RAWBDA\001076\host
for /d %%a in (%mypath%\*) do set "folderName=%%a"
echo %folderName%
for /d %%f in (%folderName%) do set myfolder=%%~nxf
echo %myfolder%
FOR /d /r %%i IN ('DIR /B %mypath%*.tif') DO (
trial.exe "%foldername%\%myfolder%_B4.tif" "%foldername%\%myfolder%_B3.tif" "%foldername%\%myfolder%_B2.tif" "%foldername%\%myfolder%_B432.tif"
)
I beleive the problem is that the FolderName and myFolder are outside the loop, but i cant get them to dynamically update within the loop.
Very grateful for some help.
The solution is simple: enumerate the subfolders and to get their names use a prefix %%~nx:
SET "MYPATH=H:\RAWBDA\001076\host"
rem Using quotes around "var=value" in case the path may contain spaces
for /d %%a in ("%mypath%\*") do (
echo Folder name: %%~nxa, full folder path: %%a
trial.exe "%%a\%%~nxa_B4.tif" "%%a\%%~nxa_B3.tif" "%%a\%%~nxa_B2.tif" "%%a\%%~nxa_B432.tif"
)

CMD deleting folder recursively (i.e. same folder name in multiple locations)

Due to a Dreamweaver setting mess-up, we've had thousands of "_notes" folders pop up in our websites dev & qa areas. There's too many to delete through Windows Explorer - everything just locks up - so I was hoping to run a batch script to sort it out for us once and for all. The problem is I'm not entirely sure that "rd /S" will do what I want.
My understanding is that rd /S will look recursively in the folder I tell it, so if I say:
rd /S r:/<siteName>/_notes/
then it will just look in the _notes folder and delete what's in there and then try to move further down that tree. What I need is a script that would take into account things like the following:
r:/<siteName>/_notes/
r:/<siteName/<someFolder>/_notes/
r:/<siteName/<someOtherFolder>/_notes/
r:/<siteName/<someFolder>/<someSubFolder>/_notes/
r:/<siteName/<someFolder>/<iThinkIveMadeMyPoint>/_notes/
Hope I made sense...
I found this in another thread, but it doesn't work with folders with a . in the name, so it's no use for site names...
#Echo OFF
REM Important that Delayed Expansion is Enabled
setlocal enabledelayedexpansion
REM This sets what folder the batch is looking for and the root in which it starts the search:
set /p foldername=Please enter the foldername you want to delete:
set /p root=Please enter the root directory (ex: C:\TestFolder)
REM Checks each directory in the given root
FOR /R %root% %%A IN (.) DO (
if '%%A'=='' goto end
REM Correctly parses info for executing the loop and RM functions
set dir="%%A"
set dir=!dir:.=!
set directory=%%A
set directory=!directory::=!
set directory=!directory:\=;!
REM Checks each directory
for /f "tokens=* delims=;" %%P in ("!directory!") do call :loop %%P)
REM After each directory is checked the batch will allow you to see folders deleted.
:end
pause
endlocal
exit
REM This loop checks each folder inside the directory for the specified folder name. This allows you to check multiple nested directories.
:loop
if '%1'=='' goto endloop
if '%1'=='%foldername%' (
rd /S /Q !dir!
echo !dir! was deleted.
)
SHIFT
goto :loop
:endloop
read HELP FOR, HELP SET and HELP IF
note that FOR /D /R will recursively walk the directory tree.
note also that %~na is the funny syntax to extract the name part of a full path.
so, putting this little pieces togethere, try this command on the command line
for /d /r %a in (*) do #if %~na==_notes #echo rd %a
after careful testing, remove the echo command.
This command has worked for me and I hope this could help. Switch to the common root folder, and type in CMD:
for /d /r . %d in (<folder name>) do #if exist "%d" rd /s/q "%d"
Change the to the name of folder you want to remove. Then all children folders with this name would be removed.

Batch script that moves each file in a folder into their own folders named after the file?

So if I have
/folder/file1.txt
/folder/file2.jpg
/folder/file3.py
I want to create
/folder/file1/file1.txt
/folder/file2/file2.jpg
/folder/file3/file3.py
I have this batch file (be careful where you run it), which mostly works but if there is whitespace in the file name, the folder name will only be named up until the whitespace and so the file won't be moved inside of it.
Also, I only got it to work by arbitrarily putting the word "Folder" or some random string at the end of the folder name, if I exclude that, for some reason it won't work. I'm on windows 7.
#echo off
for /f %%a in ('dir /a-d /b') do (
if not "%%~dpnxa"=="%~dpnx0" call :func "%%~a"
)
goto :EOF
:func
set file=%~1
set dir=%file% Folder
md "%dir%" Folder 2>nul
move "%file%" "%dir%"
goto :EOF
Any ideas on how to address the whitespace/name issues? Thanks in advance.
#echo off
for /f "usebackq delims=?" %%a in (`dir /a-d /b`) do (
if not "%%~dpnxa"=="%~dpnx0" call :func "%%~a"
)
goto :EOF
:func
set file=%~1
set dir=%file% Folder
md "%dir%" Folder 2>nul
move "%file%" "%dir%"
goto :EOF
By setting the delims=? you are saying that your delimiter is a ? to split up a string, instead of the whitespace character, which allows you to read full file names with spaces in them. Usebackq means that you instead use ` around the command to be ran, which to me, just makes it more logical to read and understand "Hey, I'm actually executing this string."
To avoid problems with spaces in paths/file names, double quote all the references to them.
The reason for having to include a string at the end of the folder in your code is you are trying to create a folder with exactly the same name that the file (in your code, you are not removing the extension), and you can not have two elements (files or folders) inside a folder with the same name.
#echo off
for %%a in ("c:\folder\*") do (
if not "%%~fa"=="%~f0" (
if not exist "%%~dpna\" echo md "%%~dpna"
if exist "%%~dpna\" echo move /y "%%~fa" "%%~dpna"
)
)
For each file in the indicated folder
if the file is not the batch file
if not exist a folder with the same name that the file, create it
if the target folder exist, move the file to the folder
%%~fa = full path of the file being processed
%~f0 = full path of the batch file
%%~dpna = drive, path, and file name without extension of the current file being proccesed
In this code, the reason for the third if is to check if the possible previous folder creation has failed. If you have a file with no extension, you will not be able to create the folder, as it will have exactly the same name as the file and this is not allowed.
Code includes echo commands before md and move to show what will be executed. If the output is correct, remove the echo to make it work.

Resources