Cycle files from different folders inside a batch - loops

In a .bat file, I've something like this:
set Files="..\DataSet\*.shp"
for /r %%i in (%Files%) do (
echo Preparing table %%i
REM other commands
)
This allows me to perform operations with every file with extension .shp inside the folder set in `%Files%.
the problem is that this is a single folder. I'd like to define different folders in the same variables, and cycle all files in them. Something like
set Files="..\DataSet1\*.shp;..\DataSet2\*.shp;..\DataSet3\*.shp"
for /r %%i in (%Files%) do (
echo Preparing table %%i
REM other commands
)
This way I should able to process every .shp file present in all folders defined in the %Files% variable. How can I change my code in order to cycle all files of specific extension in all folders defined in my variable?

#echo off
setlocal enableextensions disabledelayedexpansion
set folders="..\DataSet1" "..\DataSet2" "..\DataSet3"
set extensions=".shp"
for %%f in (%folders%) do for %%x in (%extensions%) do pushd "%%~ff" && (
for /r %%i in ("*%%~x") do (
echo Preparing table %%i
rem .....
)
popd
)
As there is no way to include the folder being iterated by for command into the /r clause of an inner for command, previous code changes the current active directory to the folder to iterate.
If changing the current active directory is a problem, the file iteration can be moved to a subroutine
#echo off
setlocal enableextensions disabledelayedexpansion
set folders="..\DataSet1" "..\DataSet2" "..\DataSet3"
set extensions=".shp"
for %%f in (%folders%) do for %%x in (%extensions%) do (
call :process "%%~ff" "%%~x"
)
goto :eof
:process folderBeingProcessed extensionToProcess
for /r "%~1" %%i in ("*%~2") do (
echo Preparing table %%i
rem .....
)
goto :eof

Related

Batch file to create folder and move file in the folder

I am in the middle of batch extracting screenshots for contents we are planning to use on a tube site I am working on.
The jpeg files per content is labled as followed:
6c82c0239f6eb839-1
6c82c0239f6eb839-2
all the way to 120
The file name is different per content
a82384e2c46ba4af-1
a82384e2c46ba4af-2
etc.
They will all be extracted to a singe folder.
So I basically need a batch file that will create folders based on the content name without the dash and number and move all 120 jpegs in the folder with the content name.
For example:
Create folder named 6c82c0239f6eb839 and
move 6c82c0239f6eb839-1 to 6c82c0239f6eb839-120 in to the created folder.
I saw another thread with the following batch file. its pretty much what I want but the folder name is only 3 characters long and the files are copied to the newly created folders instead of moving them.
#echo off
SetLocal EnableDelayedExpansion
for /F "delims=" %%a in ('dir /b *.jpeg') do (
set Name=%%a
set Folder=!Name:~0,3!
xcopy /y "%%a" !Folder!\
)
Could someone change this so that it will display full file name without the dash and number for the folders and move files in its respective folders instead of copy?
Thank you
#echo off
setlocal
#rem Get each jpeg file.
for /F "delims=" %%A in ('2^>nul dir /b *.jpeg') do (
rem Get filename as token before the dash.
for /f "delims=-" %%B in ("%%~A") do (
rem Make dir if needed.
if not exist "%%~B" md "%%~B"
rem Check if isdir.
2>nul pushd "%%~B" && popd
if errorlevel 1 (
>&2 echo Failed isdir "%%~B".
) else (
rem Do the move operation.
>nul move /y "%%~A" "%%~B"
if errorlevel 1 (
>&2 echo Failed move "%%~A" to "%%~B"
)
)
)
)
exit /b %errorlevel%
The code is well remarked so if you want to understand
the evaluated code by changing #echo off to #echo on.
The use of %errorlevel% after the exit /b is not
required though will let you know what the errorlevel is
when #echo on is used.
The pushd tests for a directory
(even if it is a symlink).
errorlevel is checked to decide if to echo a
error message or do the move.
As the for loop variables are used direct, use of
enabledelayedexpansion is not needed.
Many commands support the argument of /? to get help
about the command. i.e. move /?.
If you only try to copy the correct jpeg to the correct folder, you can do this:
#echo off
SetLocal EnableDelayedExpansion
CD <CORRECT ROOT PATH>
for /F "delims=" %%a in ('dir /b *.jpeg') do (
set Name=%%a
REM I presume all the files have 16 characters before the dash
set Folder=!Name:~0,16!
IF NOT EXIST !Folder! MKDIR !FOLDER!
xcopy /y "%%a" !Folder!\
)
I was not able to test.
First of all, I would like to apologize for my manners regarding my initial post.
The answer by micheal_heath has resolved my issue.
Furthermore, I happened to find this post by user Salmon Trout from a different site which also worked.
Batch file to make folders with part of file name and then copy files
#echo off
setlocal enabledelayedexpansion
for %%A in (*.psd *.jpg) do (
echo file found %%A
for /f "delims=" %%B in ("%%A") do set fname=%%~nB
for /f "delims=" %%C in ("%%A") do set fextn=%%~xC
for /f "tokens=1* delims=_" %%D in ("!fname!") do set folname=%%D
echo folder name !folname!
if not exist "!folname!" (
echo Folder !folname! does not exist, creating
md "!folname!"
) else (
echo Folder !folname! exists
)
echo Moving file %%A to folder !folname!
move "%%A" "!folname!"
)
echo Finished
pause
I just changed the the following line remove the hypen and numbers to create folders for the file name properly.
for /f "tokens=1* delims=-***" %%D in ("!fname!") do set folname=%%D
I still lack the knowledge on why and how both methods work, but this has been an interesting start for me. I hope other beginners trying to solve a similar issue can find something useful from this post.

How can I move files based on their name?

I'm trying to move files into existing sub-folders based on the file names.
For example, I want to move a file named AP16742 found in the directory X:\Files into a folder named AP in the directory X:\Files\AP. Other files named MO14823 I want to move into a folder named MO in the directory X:\Files\MO.
I'm inexperienced in coding, so I need explanations to go with a provided example.
This is what I tried:
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
FOR /f "delims=" %%a IN ('dir /b /a-d "%sourcedir%*.xml" ') DO (
FOR /f "tokens=1delims=_-" %%b IN ("%%a") DO (
FOR /f "delims=" %%d IN ( 'dir /b /ad "%destdir%*%%b*" ' ) DO (
ECHO(MOVE "%%a" "%destdir%\%%d\"
)
)
)
GOTO :EOF
A simple explanation would have been:
you want to distribute files in X:\Files to subfolders with the
first 2 letters of the file name.
To get a substring you need to set the content from for variable into
a normal variable.
Setting and using a variable inside a (code block) requires delayed
expansion.
#Echo off&SetLocal EnableExtensions EnableDelayedExpansion
Pushd "X:\Files"
For %%A in (*) do (
Set "File=%%~nA"
if not exist "!File:~0,2!" md "!File:~0,2!" 2>&1>Nul
Move "%%A" "!File:~0,2!"
)
Popd
In case you want to move only distinct 2 letter pairs and not all files that's also possible without great effort.
A modification of LotPings answer, this uses RoboCopy with its /MOV option, which will create directories as needed and move the files to them:
#Echo Off & SetLocal EnableDelayedExpansion
CD /D "X:\Files" 2>Nul || Exit /B
For %%A In (*) Do (Set "File=%%~nA"
RoboCopy . "!File:~,2!" "%%A" /MOV >Nul)

unable to iterate through for loop in windows batch script

Goal: Given string "CAR080 CAR085 CAR087" I need to iterate through all three cars and perform copying of files from the carname folder.
Need to copy files from individual car folders by looping through it.
Code:
#echo off
set basesource=xyz\
set year=%date:~10,4%
set destination=C:\ARWISdata\year%year%
set tempDir=DATAARWIS\DATARP_%year%
set s= CAR080 CAR085 CAR087
set t=%s%
echo t:%t%
:loop
for /f "tokens=1*" %%a in ("%t%") do (
set temp1=%%a
set SLASH=\
echo basesource:%basesource%
echo temp1:%temp1%
set source=%basesource%%temp1%%SLASH%%tempDir%
echo source:%source%
IF EXIST %source% (echo source exists)
echo destination: %destination%
IF EXIST %destination% (echo destination exists) ELSE (mkdir C:\ARWISdata\year%year%)
for /f %%a in ('xcopy /S /E /Y /D "%source%" "%destination%" ') do (
echo.Copying file '%%a'
)
set t=%%b
)
if defined t goto :loop
but it is not giving me exact solution. As it needs to take first CAR080 and perform copy operation then in next cycle it should take CAR085 and perform copying and then finally CAR087.
Need the code urgently.
Just simplify. This is equivalent to your code but without variables being set inside the for block, so you don't need delayed expansion (read here) to retrieve the value from the changed variables
#echo off
setlocal enableextensions disabledelayedexpansion
set "baseSource=xyz"
set "year=%date:~10,4%"
set "tempDir=DATAARWIS\DATARP_%year%"
set "destination=C:\ARWISdata\year%year%"
2>nul mkdir "%destination%"
for %%a in (CAR080 CAR085 CAR087) do (
xcopy "%baseSource%\%%a\%tempDir%" "%destination%"
)

Renaming .txt files in bulk

I downloaded about 34000 books in .txt format from Project Gutenberg. Now I want to rename all of them by its content. For example every text file includes its "Title" and "Author's Name" so I want to rename all the text files on its "Title" and "Author's Name" by some commands.
I created a batch file. It runs but is not renaming the files. This is my code:
#echo off&setlocal
cd E:\Test
for /f "delims=" %%i in ('dir /a-d/b *.txt') do (
set "nname="
set "fname=%%~i"
for /f "usebackqskip=7delims=" %%f in ("%%~i") do if not defined nname
set "nname=%%f"
setlocal enabledelayedexpansion
set "nname=!nname:~0,40!"
echo rename "!fname!" "!nname!"
endlocal
)
You can use this as a base
#echo off
setlocal enableextensions disabledelayedexpansion
rem Change to source folder
pushd "e:\test" && (
rem Where the renamed files will be placed to avoid re-rename
if not exist renamed\ md renamed
rem For each input file
for %%f in (*.txt) do (
rem Retrieve the data from inside the file
set "author=" & set "title="
for /f "tokens=1,* delims=: " %%a in ('
findstr /b "Author: Title:" "%%~ff"
') do if not defined %%a set "%%a=%%b"
rem If the fields have been retrieved then do the rename
if defined author if defined title (
setlocal enabledelayedexpansion
for /f "delims=" %%a in ("!author! - !title!") do (
endlocal
echo move "%%~ff" "renamed\%%a%%~xf"
rem NOTE: operation is only echoed to console
rem if console output seems correct, then
rem remove the echo command
)
)
)
rem Done. Return to previous active directory
popd
)
Of course, filesystem has rules about what is allowed in a file name and, not knowing what kind of characters can be found, this code could and probably will fail to rename some files.
Your current script will just print the rename commands, not execute them. You should remove echo (after checking what it produces) in this line:
echo rename "!fname!" "!nname!"
Your script also has a few formatting issues. There should be spaces like this:
for /f "usebackq skip=7 delims=" %%f in ("%%~i") do
And there should be no newline just after:
if not defined nname

Batch script that will insert filenames into files within multiple subfolders

I need help creating a batch script that will add the filename to the first line of every .csv within all subfolders. The batch file will be in the mainfolder. The same folder will contain several subfolders, each containing a large amount of .csv files. I need the files to stay within their respective folders. My goal is to add this to another working script I have that merges all files within a subfolder into a single .csv. This will provide a way to navigate through the merged file. I found some similar posts, but they weren't quite what I was looking for. This is the closest thing I could find but the delimiter stuff is throwing me off Batch file to Write Filename to first line
File Structure Example:
C:\MainFolder\batch_script.bat
C:\MainFolder\SubFolder1\csv1.csv
C:\MainFolder\SubFolder1\csv2.csv
C:\MainFolder\SubFolder2\csv3.csv
C:\MainFolder\SubFolder2\csv4.csv
File Contents before running script
csv1.csv:
This is the content of csv1.csv
csv2.csv:
This is the content of csv2.csv
csv3.csv:
This is the content of csv3.csv
csv4.csv:
This is the content of csv4.csv
File Contents after running script:
csv1.csv:
csv1.csv
This is the content of csv1.csv
csv2.csv:
csv2.csv
This is the content of csv2.csv
csv3.csv:
csv3.csv
This is the content of csv3.csv
csv4.csv:
csv4.csv
This is the content of csv4.csv
P.S.
I also found this code on another website but I'm not sure how I would make it loop through the different subfolders
FOR /F "usebackq tokens=1" %%i IN (`DIR /B`) DO (
ECHO %%i >> %1
TYPE %%i >> %1
)
#echo off
setlocal enableextensions disabledelayedexpansion
for /r %%a in (*.csv) do (
set /p "firstLine=" < "%%~fa"
setlocal enabledelayedexpansion
for /f "delims=" %%b in (".!firstLine!") do endlocal & if not "%%~b"==".%%~nxa" (
( echo %%~nxa
type "%%~fa"
) > "%%~fa.new"
move /y "%%~fa.new" "%%~fa" >nul
)
)
What it does is generate a new file with the name of the csv as the first line, appends the csv to the new file and moves the new file over the csv. In the process, it tests if the content of the first line is the same as the name of the csv to avoid reinclusion of the filename on each run of the batch file.
edited to adapt to comments - As the process will not be run more than once for set of csv files, the full code can be reduced to
#echo off
setlocal enableextensions disabledelayedexpansion
for /r %%a in (*.csv) do (
( echo %%~nxa
type "%%~fa"
) > "%%~fa.new"
move /y "%%~fa.new" "%%~fa" >nul
)
Try this:
for /r %%a in (*.csv) do (
copy /y "%%~a" "%temp%\%%~na"
Echo %%~na > "%%~a"
for /f "usebackq" %%b in ("%temp%\%%~na") do Echo %%b >> "%%~a"
del "%temp%\%%~na"
)
And that should do what you want it to. I would test it out first if you could.
This should create an all.csv in every folder in the tree under the C:\MainFolder and add the filename before the contents of each CSV file.
The filename will contain the full path but that can easily be changed if needed.
#echo off
for /d /r "C:\MainFolder\" %%a in (*) do (
pushd "%%a"
(for %%b in (*.csv) do (
echo %%b
type "%%b"
)
)>all.tmp
ren all.tmp all.csv
popd
)
pause

Resources