Windows batch Nested for loop issue - windows

I need to read a file in outer loop line by line, take this value and use it in inner loop. But currently I am able to read first line from this file and do some required processing in inner loop but outer loop runs only once.
Why does the outer loop run only once?
myfile.txt contains:
AWC00201
AWC00202
AWC00203
DDDD
#echo off
setlocal EnableDelayedExpansion
for /F %%D in (myfile.txt) do (
echo %D%
S:
cd \#vantage\AFG\AWC\AWCU\simulation\WRO_Regression_results\%%D
echo %%D
FOR /F %%i IN ('dir /b /ad-h /o-d') DO (
echo After Nested For
echo %%D
SET test=%%D
SET b=%%i
GOTO found
)
echo No subfolder found
goto done
:found
echo %D%
echo Most recent subfolder: %b%
cd %b%
echo %%D
find /c "O K" tooling.report
echo %D%
if %errorlevel% equ 1 goto notfound
echo found
goto done
:notfound
echo notfound
goto done
:done
echo %D%
echo now go up
echo !test!
echo %test%
)
pause
I am getting following output:
ECHO is off.
AWC00201
After Nested For
AWC00201
ECHO is off.
Most recent subfolder: 20141103_170658_wro_awc
%D
____________ TOOLING.REPORT: 0
ECHO is off.
notfound
ECHO is off.
now go up
AWC00201
AWC00201
Press any key to continue . . .

Your code has one big problem and one thing to change
The problem is that it is not possible to use goto while inside a for loop and keep the loop iterating. goto cancels the for looping.
The thing to change is your use of variables. You have the information you need inside the for replaceable parameters. Use them. Move the value to a variable when the replaceable parameters does not offer what you need, but this is not the case
#echo off
setlocal enableextensions disabledelayedexpansion
for /F "delims=" %%D in (myfile.txt) do (
cd /d "s:\#vantage\AFG\AWC\AWCU\simulation\WRO_Regression_results\%%D"
for /d %%a in (.) do echo Current folder is "%%~fa"
set "file="
FOR /F "delims=" %%i IN ('dir /b /ad-h /o-d 2 >nul ') DO if not defined file (
set "file=1"
echo subfolder found : %%i
find /c "O K" ".\%%i\tooling.report" >nul 2>nul
if errorlevel 1 (
echo O K found
) else (
echo O K not found or file does not exist
)
)
if not defined file (
echo subfolder not found
)
)
pause

Related

Looping through %1 as a directory in batch?

I've searched the web for answers but can't seem to find an answer. I want the user to provide a directory and to be able to loop through it. I'm able to loop through the current directory like so:
#Echo off
for /r %%f in (*.*) do (
echo %%f
)
But then when I try to do the same by looping through %1, I can't get the result I'm looking for. What am I doing wrong? Here's where I'm at in the batch file:
#Echo off
if exist %1 (
for /r %%f in (%1) do (
echo %%f
)
) else (
echo "That directory does not exist."
)
I've tried using /D but all that did was echo the directory I provided like this:
FileCount C:\Users\Me\Desktop
> C:\Users\Me\Desktop
Edit: My goal for this program is to eventually count the number of files within the given directory. I expect the directory to be provided as it's absolute path and I'll be executing this file through cmd. Here's an example of the input I'm expecting.
FileCount C:\Users\Me\Desktop
And the desired output would be something like:
> Hello world.txt
> Cat.png
> There are 2 files within this directory.
Side-note: I don't want to filter out the output of the dir command, I want to do this with a for loop.
Here's what you asked for, plus the optional recurs feature. Note that this will miss hidden files and directories.
#setlocal EnableExtensions
#prompt=$G
#set _Error_Success=0
#set _Error_PathNotFound=3
#if "%~1" equ "/?" goto :Usage
#if "%~1" equ "" goto :Usage
#if "%~1" equ "/r" (#set _recurs=/r & #set _root=%~2) else (#set _root=%~1)
#if not exist "%_root%" goto :Oops
#set count=0
#pushd "%_root%"
#for %_recurs% %%f in (*) do #call :Counter "%%f"
#popd
#echo There are %count% entries within this directory.
#exit /b %_Error_Success%
:Counter
#set /a count+=1
#echo %~1
#exit /b %_Error_Success%
:Oops
#echo "That directory does not exist."
#exit /b %_Error_PathNotFound%
:Usage
#echo Usage: FileCount [/r] path
And this uses the dir command, without resorting to invoking findstr:
#setlocal EnableExtensions
#prompt=$G
#set _Error_Success=0
#set _Error_PathNotFound=3
#set _Error_InvalidParameter=87
#set _attributes=
#set _recurs=
#set _count=0
#if "%~1" equ "/?" #goto :Usage & #exit
#if "%~1" equ "" goto :Usage
#set _root=%~1
#if not exist "%_root%" goto :Oops
#shift
#pushd "%_root%"
for /f %%G in ('dir /B /A-d %1 %2 %_root%') do #call :Counter "%%G"
#popd
#echo There are %_count% entries within this directory.
#exit /b %_Error_Success%
:Counter
#set /a _count+=1
#echo %~1
#exit /b %_Error_Success%
:HandleOptions
:Oops
#echo "That directory does not exist."
#exit /b %_Error_PathNotFound%
:Usage
#echo Usage: FileCount [/A<Attributes>] [/S] rootPath
#echo Where <Attributes> corresponds to 'dir /A' optiions (see 'help dir')
#echo and /S will cause recursion into subdirectories of rootPath.
This example, uses a for loop, and does not use the dir command, as per your inexplicable request, but it does use xcopy to list and count the files within it instead:
#For %%G In ("%~1") Do #If "%%~aG" Lss "d" (If "%%~aG" GEq "-" (
Echo Error: File argument given, expected a directory.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1) Else (
Echo Error: Invalid argument, directory path expected.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1)
) Else Echo File content of "%~1":& For /F Delims^= %%H In (
'%SystemRoot%\System32\xcopy.exe "%~1" : /HIL') Do #Echo %%~nxH
#%SystemRoot%\System32\timeout.exe /T -1 & Exit /B 0
If you want it to recurse the input directory, then I'd suggest this very small modification:
#For %%G In ("%~1") Do #If "%%~aG" Lss "d" (If "%%~aG" GEq "-" (
Echo Error: File argument given, expected a directory.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1) Else (
Echo Error: Invalid argument, directory path expected.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1)
) Else Echo File content of "%~1":& For /F Delims^= %%H In (
'%SystemRoot%\System32\xcopy.exe "%~1" : /HILS') Do #Echo %%H
#%SystemRoot%\System32\timeout.exe /T -1 & Exit /B 0
Or with a little more work, outputting relative paths instead:
#For %%G In ("%~1") Do #If "%%~aG" Lss "d" (If "%%~aG" GEq "-" (
Echo Error: File argument given, expected a directory.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1) Else (
Echo Error: Invalid argument, directory path expected.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1)
) Else Echo File content of "%~1":& For /F Delims^= %%H In (
'%SystemRoot%\System32\xcopy.exe "%~1" : /HILS') Do #(
Set "}=%%H" & SetLocal EnableDelayedExpansion
For %%I In ("!}:*%~1=.!") Do #EndLocal & Echo %%~I)
#%SystemRoot%\System32\timeout.exe /T -1 & Exit /B 0
setlocal enabledelayedexpansion
rem Put it into a folder that is in ENV PATH variable.
rem So, you can call it from wherever you want.
if not "%~1"=="" (
if exist "%~dpn1" (
set /a "filecount=0"
for /f "tokens=* delims=" %%f in ('dir /b "%~dpn1"') do (
echo %%f
set /a "filecount+=1"
)
echo:
echo In "%~dpn1" found !filecount! file^(s^).
) else (
echo:
echo [ERROR] Invalid input. Please specify:
echo 1. A full path.
echo 2. A folder in cwd.
echo:
echo If input is empty, current working directory (cwd)
echo will be considered.
exit /b 1
)
) else (
set /a "filecount=0"
for /f "tokens=* delims=" %%f in ('dir /b "%~dp0"') do (
echo %%f
set /a "filecount+=1"
)
echo:
echo In "%~dp0" found !filecount! file^(s^).
)
endlocal
If you want it recursive call it as progname.bat /r [foldname]:
setlocal enabledelayedexpansion
rem Put it into a folder that is in ENV PATH variable.
rem So, you can call it from wherever you want.
if "%1"=="/r" shift
if not "%1"=="" (
if exist "%~dpn1" (
set /a "filecount=0"
set /a "totalcount=0"
set "oldroot=%~dpn1"
for /f "tokens=* delims=" %%f in ('dir /b /s "!cd!"') do (
if not "%%~dpf"=="!oldroot!" (
echo:
echo In "!oldroot!" found !filecount! file^(s^).
echo:
set /a "filecount=0"
set "oldroot=%%~dpf"
)
echo --- %%f
set /a "filecount+=1"
set /a "totalcount+=1"
)
echo:
echo In "%~dpn1" found !totalcount! file^(s^).
) else (
echo:
echo [ERROR] Invalid input. Please specify:
echo 1. A full path.
echo 2. A folder in cwd.
echo:
echo If input is empty, current working directory (cwd)
echo will be considered.
exit /b 1
)
) else (
set /a "filecount=0"
set /a "totalcount=0"
set "oldroot=!cd!"
for /f "tokens=* delims=" %%f in ('dir /b /s "!cd!"') do (
if not "%%~dpf"=="!oldroot!" (
echo:
echo In "!oldroot!" found !filecount! file^(s^).
echo:
set /a "filecount=0"
set "oldroot=%%~dpf"
)
echo --- %%f
set /a "filecount+=1"
set /a "totalcount+=1"
)
echo:
echo In "%~dp0" found !totalcount! file^(s^).
)
endlocal
Try it and see if it is what you expected.
Thank you for the help everybody, I've found the solution to the problem and it was very simple. All I needed to do was loop through %1\*.* instead of %1 itself.
#Echo off
if exist %1 (
for %%f in (%1\*.*) do (
echo %%f
)
) else (
echo "That directory does not exist."
)

find multiple files paths with single string

I tried to write a batch script that find all the paths of files that have the same name as the input string. right now it can find only the first file found, and i cant think of a way to make it list multiple files locations. I am not very experienced and I need some help.
this is part of the script code:
:start
cls
echo Enter file name with extension:
set /p filename=
echo Searching...
for %%a in (C D E F G H U W) do (
for /f "tokens=*" %%b in ('dir /s /b "%%a:\%filename%"') do (
set file=%%~nxb
set datapath=%%~dpb\
::the path of the file without the filename included "C:\folder\folder\"
set fullpath=%%b
::the path of the file with the filename included "C:\folder\folder\file"
goto break
)
)
:notfound
cls
echo Enter file name with extension:
echo %filename%
echo File Not Found!
ping localhost -n 4 >nul
goto start
:break
if "%datapath:~-1%"=="\" set datapath=%datapath:~,-1%
cls
echo 3 %filename% found
echo %fullpath1%
echo %fullpath2%
echo %fullpath3%
--- || ---
I want the script to search the computer and list every encountered files with the same name and I want to be able to put those files' paths into different variables.
For example, if readme.txt is the input, then I want the list of all the paths of all the files with that specific name (readme.txt) and I want to set variable for each path so I can use it after that.
input:
readme.txt
output:
3 files found
C:\folder\folder\readme.txt
C:\folder\folder\folder\readme.txt
D:\folder\readme.txt
#echo off
set filename=readme.txt
for %%a in (C D E F G H U W) do (
for /f "tokens=*" %%b in ('dir /s /b "%%a:\%filename%"') do (
echo you can do something here with %%~nxb in %%~dpb
echo full name: %%b
)
)
I see no need to set the filenames to variables, as you can process them inside your loop. But if you really need them (for some reason) in variables:
#echo off
setlocal enabledelayedexpansion
set filename=readme.txt
set count=0
for %%a in (C D E F G H U W) do (
for /f "tokens=*" %%b in ('dir /s /b "%%a:\%filename%" 2^>nul') do (
set /a count+=1
set _file[!count!]=%%b
)
)
set _file
You can try with this code :
#echo off
Title Searching for the path with the same file name
Mode con cols=80 lines=3 & Color 9E
SET /a Count=0
set /a cnt=1
set "FileName=Readme.txt"
set "Report=%~dp0Report.txt"
set "Folder2Copy=%~dp0Readme_Folder"
set "Result2Copy=%~dp0Result2Copy.txt
If exist %Folder2Copy% RD /S /Q %Folder2Copy%
If Exist %Report% Del %Report%
If Exist %Result2Copy% Del %Result2Copy%
echo(
Echo Searching for the path with the same file name
Rem Looking for fixed drives and store them into variables
SETLOCAL enabledelayedexpansion
For /f "skip=1" %%a IN ('wmic LOGICALDISK where driveType^=3 get deviceID') DO (
for /f "delims=" %%b in ("%%a") do (
SET /a "Count+=1"
set "Drive[!Count!]=%%b"
)
)
:Display
for /L %%i in (1,1,%Count%) do (
cls
Title Please wait a while ... Searching for "%FileName%" on "!Drive[%%i]!\"
echo(
echo Please wait a while ... Searching for "%FileName%" on "!Drive[%%i]!\"
Call :FindPathFile !Drive[%%i]!\ %FileName% >> %Report%
)
Start "" %Report%
Goto :AskQuestion
::***************************************************************************************
:FindPathFile <Location> <FileName>
Where.exe /r %1 %2
Goto :eof
::***************************************************************************************
:AskQuestion
cls & Mode con cols=100 lines=5
echo(
echo Did you want to make copy of all files found as name "%FileName%"
echo saved on "%Report%" ? (Y/N) ?
set /p "Input="
If /I "%INPUT%"=="Y" (
for /f "delims=" %%i in ('Type "%Report%"') do (
Call :MakeCopy "%%~i" "%Folder2Copy%\"
)
)
Call :Explorer "%Folder2Copy%\" & exit
If /I "%INPUT%"=="N" (
Exit
)
Goto :eof
::***************************************************************************************
:MakeCopy <Source> <Target>
If Not Exist "%~2\" MD "%~2\" (
if not exist "%2\%~n1" (
echo copying "%~1" to "%~2"
copy /N /B "%~1" "%~2" >>%Result2Copy% 2>&1
) else (
call :loop "%~1" "%~2"
)
)
::***************************************************************************************
:loop
set "fname=%2\%~n1(%cnt%)%~x1"
if exist "%fname%" set /a cnt+=1 && goto :loop
copy "%~1" "%fname%"
exit /b
::***************************************************************************************
:Explorer <file>
explorer.exe /e,/select,"%~1"
Goto :EOF
::***************************************************************************************

Windows batch For Loop dropping empty strings to the end

I have this following code.
#echo off
setlocal EnableDelayedExpansion
set holdingline=,Measure,,+ X,,,0,0
FOR /F "tokens=1,2,3,4,5,6,7,8 delims=," %%a IN ("%holdingline%") DO (
echo %%a
echo %%b
echo %%c
echo %%d
echo %%e
echo %%f
echo %%g
echo %%h
echo %holdingline%
)
pause
Output displayed is as below:
Measure
+ X
0
0
ECHO is off.
ECHO is off.
ECHO is off.
ECHO is off.
,Measure,,+ X,,,0,0
The empty strings are pushed to the end and I wonder why. I am expecting them in order, say something like:
ECHO is off.
Measure
ECHO is off.
+ X
ECHO is off.
ECHO is off.
0
0
,Measure,,+ X,,,0,0
This would enable me to assign them to the correct variables. I tried searching but did not find much help.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
set holdingline=,Measure,,+ X,,,0,0
FOR /F "tokens=1-8 delims=," %%a IN (""%holdingline:,=","%"") DO (
ECHO(%%~a
ECHO(%%~b
ECHO(%%~c
ECHO(%%~d
ECHO(%%~e
ECHO(%%~f
ECHO(%%~g
ECHO(%%~h
echo %holdingline%
)
GOTO :EOF
This should solve your problem
To process a file, producing a new file
#ECHO OFF
SETLOCAL
(
FOR /f "delims=" %%x IN (q29639243.txt) DO (
set "holdingline=%%x"
CALL :process
)
)>u:\new.txt
GOTO :EOF
:process
FOR /F "tokens=1-8 delims=," %%a IN (""%holdingline:,=","%"") DO (
ECHO(%%~a
ECHO(%%~b
ECHO(%%~c
ECHO(%%~d
ECHO(%%~e
ECHO(%%~f
ECHO(%%~g
ECHO(%%~h
echo %holdingline%
)
GOTO :EOF
I used a file named q29639243.txt containing similar data for my testing.
Produces u:\new.txt
This should do what you want it to:
#echo off
setlocal EnableDelayedExpansion
set holdingline=,Measure,,+ X,,,0,0
FOR /F "tokens=1,2,3,4,5,6,7,8 delims=," %%a IN ("%holdingline:,,=, ,%") DO (
echo %%a
echo %%b
echo %%c
echo %%d
echo %%e
echo %%f
echo %%g
echo %%h
echo %holdingline%
)
pause
Replacing ,, with , , will cause it to set the middle variables to (space) and hence treat them like nothing. If you don't have anything between two , it will skip them and hence only 4 variables exist, leaving e-h blank

Replace a line with another line using IF - Batch file

I am trying to replace a line in load.xml using the lines read from FileList.txt.
Contents of load.xml
<mainheader>
<InFilePath>D:\Data\All_Inputfiles\oldfile.txt</InFilePath>
</mainheader>
FileList.txt
newfile1.txt
newfile2.txt
Expecting the output with each iteration as
<mainheader>
<InFilePath>D:\Data\All_Inputfiles\newfile1.txt</InFilePath>
</mainheader>
and with the next iteration replace newfile1.txt with newfile2.txt. I am able to get original string with the final string but last part of the code is throwing syntax error, i.e. from
for /f "delims=" %%a in (!INTEXTFILE!) do call :Change "%%a" .
Could please help me?
Thanks in advance.
#echo off
SETLOCAL EnableDelayedExpansion
Set AllInputFile= D:\data\FileList.txt
SET INTEXTFILE=C:\c:\load.xml
set OUTTEXTFILE=D:\data\tmp_out.txt
SET BackupPath=D:\data\backupload.xml
Set TempFile=D:\data\tmp.txt
SET DbgFile=D:\data\debuginfo.txt
Del !TempFile!
Del !DbgFile!
Copy !INTEXTFILE! !BackupPath!
:replace
findstr /g "InFilePath" !INTEXTFILE!>!TempFile!
:: set string=" <InFilePath>D:\Data\All_Inputfiles\oldfile.txt</InFilePath>"
set /p string=< !TempFile!
SET PREVFILE_NM=!string:~75,-13!
set FinalreplaceLine=!string!
set TARG_FILE=%~1
REM ECHO "Before Replace FinalreplaceLine "!FinalreplaceLine!>>!DbgFile!
set FinalreplaceLine=!FinalreplaceLine:%PREVFILE_NM%=%TARG_FILE%!
ECHO "string "!string!>>!DbgFile!
ECHO "FinalreplaceLine "!FinalreplaceLine!>>!DbgFile!
::string has source string and FinalreplaceLine has target string to replace
for /f "delims=" %%a in (!INTEXTFILE!) do call :Change "%%a"
exit /b
:Change
set Text=%~1
if "%Text%"=="%string%" (
(echo !FinalreplaceLine!)>> !OUTTEXTFILE!
) else (
(echo !Text!)>> !OUTTEXTFILE!
)
exit /b
Does this work for you?:
#echo off
for /f "usebackq delims=" %%a in ("FileList.txt") do (
call :change "%%a"
type "load.xml"
pause
)
echo done
pause
goto :EOF
:change
(
echo ^<mainheader^>
echo ^<InFilePath^>D:\Data\All_Inputfiles\%~1^</InFilePath^>
echo ^</mainheader^>
) > "load.xml"

for command is executed only for the first value when a label is inside

I have the script
for /f "delims=" %%i in ('dir "%folder%*.txt" /b /s') do (
set s=%%i
set s=!s:%folder%=!
set new_s=!s:\=!
if "x!new_s!" NEQ "x!s!" (
:ProcessListSource
For /f "tokens=1* delims=\" %%A in ("!s!") do (
if "%%A" NEQ "" (
if "!Folder1!" NEQ "" (
Set Folder1=!Folder1!\!Name!
)else (
Set Folder1=!Name!
)
Set Name=%%A
)
if "%%B" NEQ "" (
set s=%%B
goto :ProcessListSource
)
)
echo Folder is: !Folder1!
echo Name is: !Name!
echo ---------------------
) else (
echo Not a folder !s!
)
)
but it does not work as I would have expected:
The first for is executed only once and also the last echo is printed on the screen.
Given a folder I need the files from subfolders without the given folder and than split them into the folder and file
Ex: folder=C:\test
The for would give me the file C:\test\test1\test2\t.txt
And I need test1\test2 and t.txt
GOTO breaks your FOR /F \ IF context and they can be executed only once.
More simple example:
#echo off
for /l %%S in (1=1=5) do (
echo %%S
goto :inner_label
rem
:inner_label
rem
)
This will print only 1 . Do you really need the GOTO here?
When the parser reads your code, all the code inside your for loop is "considered" as only one command that is readed, parsed and executed. As stated in the npocmaka answer, any goto call takes you out of this "line" of code, ending the process of the for loop.
This is a alternative. Use pushd + xcopy /l /s commands to generate a list of the relative paths of the files.
#echo off
setlocal enableextensions disabledelayedexpansion
set "folder=%cd%"
pushd "%folder%"
for /f "delims=" %%a in ('xcopy /l /s /y * "%temp%"^|findstr /vbr /c:"[0-9]"'
) do for /f "delims=: tokens=1,*" %%b in ("%%~a") do (
echo [%%c] [%%~nxa]
)
popd

Resources