Batch nested loop doesn't work - batch-file

I'm trying to make a mod loader for a game in batch but I can't get it to work with a nested loop.
The command used is this loadMods.bat mod1.txt mod2.txt ... modN.txt
This is the code I'm using
setlocal EnableDelayedExpansion
set /p outputFile="Output File:"
for %%x in (%*) do (
echo Applying mod from file %%x
for /f "delims=" %%y in (%%x) do echo %%y >> %fileOutput%
)
echo Finished.
pause
The second loop works fine if it's outside the first loop but when I use nested loops I get an The syntax of the command is incorrect. error on the second loop.

As #SomethingDark said, this is caused by a simple typographical issue.
for /f "delims=" %%y in (%%x) do echo %%y >> %fileOutput%
The variable fileoutput was undefined, making the CMD.EXE sees:
for /f "delims=" %%y in (%%x) do echo %%y >>
and it cannot find an argument after >>, causing the error.
By the way, when debugging batch files, I'd recommend:
remove #echo off
run script from CMD.exe
These method shows exactly which command(s) go wrong, making debugging easier.

As you appear only to be copying the contents of several files to a single output file you could probably simplify things a little too.
#Echo Off
If "%~1"=="" Exit/B
Set/P "outputFile= Output File: "
Type %* 2>Nul >"%outputFile%"
Echo( Finished.
Pause
Ensuring the validity of any passed arguments and input string is your responsibility.
You could even possibly bypass the input parameters:
#Echo Off
Set/P "outputFile= Output File: "
Type mod*.txt 2>Nul >"%outputFile%"
Echo( Finished.
Pause

Related

how to get the list of files from the directory one by one into a variable

I am new to Batch script,
by using the following code
setlocal enabledelayedexpansion enableextensions
set LIST=
for %%x in (D:\all_files\*.csv) do set LIST=!LIST! %%x
set LIST=%LIST:~1%
echo %LIST%
i am getting the filenames with directory and also with a Paragraph
but i need file names alone one by one like below into a Variable of %LIST%
file1.csv
file2.csv
file3.csv
can any one please help us
I hope, I got your intentions right.
Instead of a variable, just loop over output of dir /b
:loop
echo still waiting...
timeout /t 10
set "ok=yes"
for /f "delims=" %%a in ('dir /b "D:\all_files\*.csv"') do (
if not exist "C:\%%a" set "ok=no"
)
if "%ok%" == "no" goto :loop
echo all there...
call process1.bat

Nested for loop - batch Script

Hello Batch File experts,
I wrote this piece of code which will print the Latest file version present in the folder in comparison to file name sent as argument, however these line seems to work accordingly when I remove the outer for loop, which I designed to loop as many time as CLI arguments.
FOR /f %%f IN ('DIR /b %%a.*.zip') DO #SET last=%%f
ECHO %last%
Full code :
cd C:\Users\batch\Desktop\test
chdir
set arg1=%1
set arg2=%2
set list=%arg1% %arg2%
(for %%a in (%list%) do (
FOR /f %%f IN ('DIR /b %%a.*.zip') DO #SET last=%%f
ECHO %last%
))
pause
what am I missing here because of which variable last is not set with value when outer loop is present which works perfectly without it.
Thanks,
Might I suggest you use SHIFT instead:
#Echo Off
SetLocal
If %1'==' Exit/B
If /I Not "%CD%"=="%USERPROFILE%\Desktop\test" (
PushD "%USERPROFILE%\Desktop\test" 2>Nul&&(Set _=PopD)||Exit/B)
:Loop
For %%A In ("%~1*.zip") Do Set "last=%%A"
Echo=%last%
Shift
If Not %1'==' GoTo Loop
%_%
EndLocal
Timeout -1
This of course means that you are free to use it with more than two arguments!
You need to use delayed expansion (about ten thousand SO items on this) or use a subroutine or
call echo %%last%%

Windows CMD Batch: FOR /R with DelayedExpansion

On my desktop, there is a folder named "test". Inside this folder is two files, "file1.txt" and "file2.txt".
Take a look at this simple batch script:
#ECHO OFF
SET test="C:\Users\Tyler\Desktop\test"
ECHO %test%
FOR /R %test% %%F IN (*) DO (
ECHO %%F
)
As you might expect, it outputs the following:
"C:\Users\Tyler\Desktop\test"
C:\Users\Tyler\Desktop\test\file1.txt
C:\Users\Tyler\Desktop\test\file2.txt
Now take a look at this variation:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET test="C:\Users\Tyler\Desktop\test"
ECHO !test!
FOR /R !test! %%F IN (*) DO (
ECHO %%F
)
ENDLOCAL
I would expect its output to be no different. However, here it is:
"C:\Users\Tyler\Desktop\test"
It appears that !test! gets expanded in the ECHO !test! line, but not in the FOR /R !test! line, becoming just !test!. Since that is, of course, not a valid path, the FOR /R loop never iterates.
Why is this? What am I missing?
Why FOR works different than ECHO is because the batch parser (cmd.exe) has special parsing rules for FOR, IF and REM.
Therefore delayed expansion doesn't work for the parameters here, only for the arguments inside the parenthesis.
Only percent expansion works for the parameters, as the parser executes the percent expansion phase just before it switches to the special FOR parser rules.
If you can't use percent expansion, as you are inside of a block you can move the code to an own function and call it.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET test="C:\Users\Tyler\Desktop\test"
ECHO !test!
call :doMyLoop test
exit /b
:doMyLoop
set "arg=!%1!"
FOR /R %arg% %%F IN (*) DO (
ECHO %%F
)

Issue with environment variable in batch script

So, I have probably a simple question but I cannot seem to find an easy answer.
Issue: I have a file that contains a set of lines such as:
%windir%\file.exe
%windir%\file2.dll
and so forth...
What I am trying to do is echo the actual file path to a second file such that the resulting output would be something like:
C:\Windows\file.exe
C:\Windows\file2.dll
and so forth...
The actual source file could have other variables such as %programfiles% but all of them have a resulting actual path.
I am currently using a for /f loop but when I echo the variable, I just get the environment variable returned rather than the actual path to the file.
Is there a solution out there for batch scripting?
The actual script is below. Note I am all for making this more efficient as time to get the information is important.
#echo off
setlocal enabledelayedexpansion
reg.exe query "HKLM\System\CurrentControlSet\Services" >> registry_hklm_installed_services_tmp.txt 2>nul
reg.exe query "HKLM\System\ControlSet001\Services" >> registry_hklm_installed_services_tmp.txt 2>nul
reg.exe query "HKLM\System\ControlSet002\Services" >> %temp_outpath%\registry_hklm_installed_services_tmp.txt 2>nul
reg.exe query "HKLM\System\ControlSet002\Services" >> registry_hklm_installed_services_tmp.txt 2>nul
for /f "delims=?" %%a in (registry_hklm_installed_services_tmp.txt) do (
set regkey=%%a
call :getvalue
)
goto :parsereg
:getvalue
reg.exe query "!regkey!\Parameters" /v ServiceDll > nul 2>&1 && goto regkeyexist
goto :eof
:regkeyexist
for /f "tokens=2*" %%b in ('reg.exe query "!regkey!\Parameters" /v ServiceDll') do set ImagePath=%%c
call :regag
goto :eof
:regag
echo !ImagePath! >> registry_hklm_installed_services_tmp2.txt
goto :eof
:parsereg
for /f "delims=?" %%a in (registry_hklm_installed_services_tmp2.txt) do echo %%a >> registry_hklm_installed_services_tmp3.txt
You can use the for /f command to cycle through the lines in the file like you are doing, and pass the line from the file to a subroutine inside the batch file, which will resolve it while it is being passed. Give the following:
Test.txt
%windir%\test.txt
%programfiles%\Test2.txt
This batch file will resolve the environment variables:
#echo off
setlocal ENABLEDELAYEDEXPANSION
for /f "delims=" %%i in (Test.txt) do call :Expand "%%i"
endlocal
goto TheEnd
:Expand
set _var=%1
echo !_var:"=!
:TheEnd
This is how the output looks when you run it:
c:\>Test.bat
C:\Windows\test.txt
C:\Program Files (x86)\Test2.txt
You can redirect the result to a new text file like this:
Test.bat > NewFile.txt
Or you can modify the original Test.bat to output the modified filename under Expand instead of echoing it to the console. It is important to include the quotes around %%i ("%%i") or spaces in the resolved paths will break into multiple variables when calling Expand (e.g., %1, %2, %3, etc.). The !_var:"=! removes the quotes.
This will also expand the variables.
#echo off
for /f "delims=" %%a in (Test.txt) do call echo %%a
pause
Test.txt
%windir%\test.txt
%programfiles%\Test2.txt
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%a IN (q22726616.txt) DO (
FOR /f "delims=" %%b IN ('echo %%a') DO (
ECHO %%b
)
)
GOTO :EOF
I used a file named q22726616.txt containing your data for my testing.
[fixed following response - %%b line]

How can we remove the leading and traling spaces from a string in batch script?

I have a first.properties file and I am reading that file, skipping the first 5 lines and creating a new file with the remaining lines of first.properties. This is working fine. But I am getting spaces for each line in the newly created file. I want to remove these spaces.
I have used the following piece of code:
#echo off
set new=0
setlocal ENABLEDELAYEDEXPANSION
for /F "skip=5" %%L in (first.properties) do (
echo %%L>>NewProjectsInfo.properties
)
endlocal
pause
first.properties is as follows:
name=abcd
number=bcde
address=cdef
mobile=efgh
worklocation=ghij
Please help me out to remove the spaces.
Try this. There can be issues when numbers directly precede the >> characters.
You are not using ENABLEDELAYEDEXPANSION so I removed it too.
#echo off
set new=0
setlocal
for /F "skip=5 delims=" %%L in (first.properties) do (
>>NewProjectsInfo.properties echo %%L
)
endlocal
pause
There is a space after NewProjectsInfo.properties in your code. if that is removed, it works as you expect.
It's sad, but looks like, batch interprets command as entire line & separates out the redirection part. In bash, for example, the command terminates at > symbol itself.
e.g. echo hello >somefile.txt world will put hello world in somefile.txt.
#ECHO OFF
SETLOCAL
(
FOR /f "skip=5 delims=" %%i IN (rltsf.txt) DO CALL :unpad %%i
)>output.txt
FC rltsf.txt output.txt
GOTO :eof
:unpad
ECHO %*
GOTO :eof
This approach seemst to work, but I fancy it may be a little sensitive to line-content. Easier to test if we have representative data...

Resources