Variable substring Edit/Replace inside a for loop - windows

I want to replace a variable's substring, previously stored on a variable inside a for loop, I tried to do it like this but it didn't work:
setlocal EnableDelayedExpansion
set checkVar=abcd
FOR %%Y IN (*.pdf) DO (
SET meu=%%Y
CALL SET meuWithoutChar=!meu:%%%checkVar%%%=!
ECHO meuWithoutChar=!meuWithoutChar!
)
For example here if %%Y==blepabcdnnnn.pdf; I want to have meuWithoutChar=blepnnnn.pdf on the output
Thank you in advance

You are bit confused on the concept of delayed expansion and the use of CALL to get an extra phase of expansion. Here are the examples. I am just using your single file example. You can change it back to using the wildcard.
CALL example
#echo off
set checkVar=abcd
FOR %%Y IN (blepabcdnnnn.pdf) DO (
SET "meu=%%Y"
CALL SET "meuWithoutChar=%%meu:%checkVar%=%%"
CALL ECHO meuWithoutChar=%%meuWithoutChar%%
)
pause
Delayed Expansion
#echo off
setlocal Enabledelayedexpansion
set checkVar=abcd
FOR %%Y IN (blepabcdnnnn.pdf) DO (
SET "meu=%%Y"
SET "meuWithoutChar=!meu:%checkVar%=!"
ECHO meuWithoutChar=!meuWithoutChar!
)
pause

As a supplement/extension to Squashmans answer.Only cycles through necessary files and ignores the file's extension.
Without delayed expansion:
#Echo Off
SetLocal DisableDelayedExpansion
Set "strChr=abcd"
For %%A In ("*%strChr%*.pdf") Do (Set "objFileName=%%~nA"
Call Set "objNewFile=%%objFileName:%strChr%=%%%%~xA"
Call Echo %%%%objNewFile%%%%=%%objNewFile%%)
Pause
With full script delayed expansion, (will have issues with filenames containing !'s):
#Echo Off
SetLocal EnableDelayedExpansion
Set "strChr=abcd"
For %%A In ("*%strChr%*.pdf") Do (Set "objFileName=%%~nA"
Set "objNewFile=!objFileName:%strChr%=!%%~xA"
Echo %%objNewFile%%=!objNewFile!)
Pause
With toggled delayed expansion, (protects filenames containing !'s):
#Echo Off
SetLocal DisableDelayedExpansion
Set "strChr=abcd"
For %%A In ("*%strChr%*.pdf") Do (Set "objFileName=%%~nA"
SetLocal EnableDelayedExpansion
Set "objNewFile=!objFileName:%strChr%=!%%~xA"
Echo %%objNewFile%%=!objNewFile!
EndLocal)
Pause

Related

Keep variable after endlocal in Batch

I have a folder structure, which is like for example C:\Temp\ and there are a lot of folder and file, and within each folder there are a "callme.bat". I would like to create a so called main.bat which is one after another call the callme files within the main' window. But there is a problem, within the callme files are some echo which contains "!" mark what make a problem for me.
I realized the problem with the setlocal-endlocal combo, because the batch scrip wants to interpret the message within the "!" marks, so I must use endlocal, but if I did I not able to run the callme bats.
callme.bat
#echo off
echo !!! hidden message !!! not hidden message
pause
main.bat variant 1
#echo off
setlocal enabledelayedexpansion
set PATH=C:\Temp
for /F %%x in ('dir /B/A:D %PATH%') do (
set CURR_DIR=%PATH%\%%x
set ACTUAL_BATCH=!CURR_DIR!\callme.bat
echo !ACTUAL_BATCH!
call !ACTUAL_BATCH!
pause
)
pause
exit
main.bat variant 2
#echo off
set PATH=C:\Temp
for /F %%x in ('dir /B/A:D %PATH%') do (
setlocal enabledelayedexpansion
set CURR_DIR=%PATH%\%%x
set ACTUAL_BATCH=!CURR_DIR!\callme.bat
echo !ACTUAL_BATCH!
ENDLOCAL & SET VAR=!ACTUAL_BATCH!
echo %VAR%
pause
)
pause
exit
main.bat variant 3
#echo off
set PATH=C:\Temp
for /F %%x in ('dir /B/A:D %PATH%') do (
setlocal enabledelayedexpansion
set CURR_DIR=%PATH%\%%x
set ACTUAL_BATCH=!CURR_DIR!\callme.bat
echo !ACTUAL_BATCH!
REM source: https://stackoverflow.com/questions/3262287/make-an-environment-variable-survive-endlocal
for /f "delims=" %%A in (""!ACTUAL_BATCH!"") do endlocal & set "VAR=%%~A"
echo %VAR%
call %VAR%
pause
)
pause
exit
So I don't know what to do. Anyone has an idea?
variant 1's output:
C:\Temp\1\callme.bat
not hidden message
C:\Temp\2\callme.bat
not hidden message
variant 2-3's output:
C:\Temp\1\callme.bat
ECHO is off.
C:\Temp\2\callme.bat
ECHO is off.
TL;DR
ENDLOCAL&set "varname=%sourcevarname%"
probably, where varname is the variablename to set and sourcevarname is the variable whose value is to be assigned to varname - and they CAN be the same name, even if the statement appears logically null - it's exporting the variable from within the setlocal/endlocal block.
Key point: MUST be on one physical line and may be repeated if necessary (ie
ENDLOCAL&set "varname=%sourcevarname%"&set "varname2=%sourcevarname2%"
So
ENDLOCAL&set "fred=%fred%"&set "bill=%george%"
is perfectly valid, to set the value of fred outside the setlocal/endlocal bracket to its final value inside and of billoutside to the final value of george inside.
Some points about your code:
Never use PATH as a variable name, as it destroys the PATH variable for searching executable files.
Use the extended SET syntax set "varname=content" to avoid problems with trainling spaces.
You only need to disable the delayed expansion mode by using setlocal DisableDelayedExpansion
#echo off
setlocal EnableDelayedExpansion
set MY_PATH=C:\Temp
for /F %%x in ('dir /B/A:D %PATH%') do (
set "CURR_DIR=%MY_PATH%\%%x"
set "ACTUAL_BATCH=!CURR_DIR!\callme.bat"
call :execute ACTUAL_BATCH
pause
)
pause
exit /b
:execute ACTUAL_BATCH
set "batFile=!%~1!"
echo Calling !batFile!
setlocal DisableDelayedExpansion
call %batFile%
endlocal
exit /b

Find and replace string with a portion of the filename in multiple files within a folder using windows Batch script

I have a batch file to Find and replace text string in a file with a portion of the its own file-name in multiple files within a folder using windows Batch script but it does not work and simply replace YYY with null or nothing. Any help appreciated. thank you
#echo off
SETLOCAL
SET stringtofindreplace=YYY
for %%f in (*.fmw) do (
#echo Processing %%f...
fOR /F "delims=" %%l IN (%%f) DO (
SET "line=%%l"
SET fname=%%~nf
SET fname=!fname:~6,3!
SETLOCAL ENABLEDELAYEDEXPANSION
set "x=!line:%stringtofindreplace%=%fname%!"
echo(!x!
ENDLOCAL)
)>%%~nf.txt
)
GOTO:EOF
here is updated code that still does not work
#echo off
SETLOCAL
SET stringtofindreplace=YYY
for %%f in (*.fmw) do (
#echo Processing %%f...
(
fOR /F "delims=" %%l IN (%%f) DO (
SET "line=%%l"
SET fname=%%~nf
SETLOCAL ENABLEDELAYEDEXPANSION
SET fname=!fname:~6,3!
SET "x=!line:%stringtofindreplace%=%fname%!"
echo(!x!
ENDLOCAL
)
)>%%~nf.txt
)
GOTO:EOF
You have a number of problems.
1) Your name substring computation attempts to use delayed expansion within your loop before you enable it.
2) The computed replacement string cannot be expanded using normal expansion. You need delayed expansion there as well. But you cannot use delayed expansion within delayed expansion. The trick is to transfer the inner value to a FOR variable.
3) You have got an extra, unbalanced ) after ENDLOCAL. I don't think it is causing any problems with the code you have posted, but you probably should remove it.
You are also computing the name substring once for every line, when it really only need be done once per file. This isn't a bug, but it is inefficient.
Here is corrected code.
#echo off
setlocal
set stringtofindreplace=YYY
for %%f in (*.fmw) do (
#echo Processing %%f...
setlocal enableDelayedExpansion
set "fname=%%~nf"
for /f "eol=: delims=" %%A in ("!fname:~6,3!") do (
endlocal
for /f "delims=" %%l IN (%%f) do (
set "line=%%l"
setlocal enableDelayedExpansion
set "x=!line:%stringtofindreplace%=%%A!"
echo(!x!
endlocal
)
)>"%%~nf.txt"
)
You still could have problems if any lines begin with ;. Also, empty lines will be stripped. Both limitations could be solved with a bit more code.
But even if you fix the limitations, it will be quite slow. It could be painfully slow if any files are large.
The code is much simpler, faster, and more reliable if you use my hybrid JScript/batch REPL.BAT utility:
#echo off
setlocal
set stringtofindreplace=YYY
for %%f in (*.fmw) do (
#echo Processing %%f...
setlocal enableDelayedExpansion
set "fname=%%~nf"
type "!fname!.fmw"|repl "%stringtofindreplace%" "!fname:~6,3!" li >"!fname!.txt"
endlocal
)

Using Windows Batch Script Can I Use A For Loop To Iterate Multi-Line File And Run Multiple Commands

I would like to iterate a flat text file containing a Windows directory listing and run multiple commands against each line assigning each line to a variable. I then want to echo each resulting output from each command into a comma-delimited file. Yes, I understand batch programming might not be the best choice but am somewhat limited at the moment. Here is where I am at with it:
#echo off
setlocal
SETLOCAL ENABLEDELAYEDEXPANSION
:: There could be spaces in the filename, thus using delims
FOR /f "delims=?" %%a in (e:\multiline_textfile.txt) do (
set filename=%%a
CALL :PROG1
CALL :PROG2
CALL :PROG3
CALL :ENDPROG
:PROG1
FOR /f "delims=?" %%h in ('e:\apps\exe1.exe -s "!filename!"') do set result11=%%h
:PROG2
FOR /f "delims=?" %%i in ('e:\apps\exe1.exe -b"!filename!"') do set result2=%%i
:PROG3
FOR /f "delims=?" %%j in ('e:\apps\exe2.exe -c "!filename!"') do set result3=%%j
:ENDPROG
echo !result1!,!result2!,!result3!
)
---
Any insight would be greatly appreciated.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
:: There could be spaces in the filename, thus using delims
FOR /f "delims=" %%a in (e:\multiline_textfile.txt) do (
set "filename=%%a"
CALL :PROG1
CALL :PROG2
CALL :PROG3
CALL :ENDPROG
)
echo here endeth your batch mainline
goto :eof
:PROG1
FOR /f "delims=" %%h in ('e:\apps\exe1.exe -s "!filename!"') do set "result1=%%h"
goto :eof
:PROG2
FOR /f "delims=" %%i in ('e:\apps\exe1.exe -b"!filename!"') do set "result2=%%i"
goto :eof
:PROG3
FOR /f "delims=" %%j in ('e:\apps\exe2.exe -c "!filename!"') do set "result3=%%j"
goto :eof
:ENDPROG
echo !result1!,!result2!,!result3!
goto :eof
You don't need the initial SETLOCAL - one is quite sufficient.
Labels are simply MARKERS in a batch program - they don't affect flow. The most common way to return in a CALLed routine is to GOTO :EOF where the colon is REQUIRED and the label :EOF is implicit and should NOT be declared.
Bad idea to attempt to use labels within a FOR loop like that. Might work with later versions, but not with earlier. Note the FOR loop's ending ) has been moved...
Whereas !var! works, it is not necessary in this case because each subroutine is essentially a whole new program which inherits the main environment as it stood at the CALL. Hence each !var! could be replaced by %var% and the SETLOCAL ENABLEDELAYEDEXPANSION need only be a SETLOCAL. You only need to use delayedexpansion where an ordinary environment variable's value is to be used after being changed in a compound statement (like a FOR over multiple lines, for instance)

Windows batch: delayed expansion in a for loop

I want to modify a few specific lines of numbers of text files, and I wrote a batch file as follows:
#echo off
set n=0
set n1=10
set n2=40
cd.>output.txt
for /f "delims=" %%i in ('findstr /n .* test.txt') do (
set "var=%%i"
setlocal enabledelayedexpansion
set /a n=!n!+1
echo.!n!
set var=!var:*:=!
rem if !n!=%n1% ...
rem if !n!=%n2% ...
(echo.!var!)>>output.txt
endlocal
)
start output.txt
However, this doesn't work as expected.
After some tests, I think the !n! expansion is not normally delayed. That is very strange, because !var! expansion is normally delayed.
By the way, the setlocal enabledelayedexpansion and endlocal commands are put in the for loop, because otherwise the special character ! will be abandoned.
I suppose the problem what you see is that n will never increase.
But that isn't a problem of the delayed expansion, it's an effefct of the setlocal/endlocal block inside the loop.
As #panda-34 mentioned you should use the extended syntax of set/a and move the statement outside the setlocal/endlocal block.
#echo off
set n=0
set n1=10
set n2=40
(
for /f "delims=" %%i in ('findstr /n .* test.txt') do (
set "var=%%i"
set /a n+=1
setlocal enabledelayedexpansion
echo !n!
set var=!var:*:=!
rem if !n!=%n1% ...
rem if !n!=%n2% ...
(echo(!var!)
endlocal
)
) >output.txt
start output.txt

Concatenate file paths to variable in batch script

I have a script that I've put together that should copy the list of files to a variable but the only thing I receive is the last file. In other words, when I echo the variable in my for loop, I see 20 or so files but only the last one gets copied to my variable. How can I get them all to copy correctly?
I am using Windows 7.
#echo off
setlocal enabledelayedexpansion enableextensions
for /r %%x in (*) do (
echo %%x
SET PATH_VALUE=%%x;%PATH_VALUE%
)
One way is to use delayed expansion. You've enabled it – half the job done. Now you only want to use it. Replace the %s around PATH_VALUE with !s and you are done:
#echo off
setlocal enabledelayedexpansion enableextensions
for /r %%x in (*) do (
echo %%x
SET PATH_VALUE=%%x;!PATH_VALUE!
)

Resources