Delayed expansion not working for a for loop - batch-file

I have this batch script and I am calling another batch script "Strip_Batch.bat" and passing %Stripped_Name% variable as parameter. But this parameter doesnt work. Any idea how I can pass this variable?
#echo off
setlocal enableextensions enableDelayedExpansion
set CONFIGURATIONS=HAVING_FUN_WITH_COLLEGUES
for %%i in (%CONFIGURATIONS%) do (
set Original_Name=%%i
echo !Original_Name!
set Stripped_Name=!Original_Name:~0,-14!
echo !Stripped_Name!
call Strip_Batch.bat %%i %Stripped_Name%
if errorlevel 1 goto error_exit
)
:the_end
endlocal
exit /b 0
:error_exit
endlocal
exit /b 1

according to my comment I'd suggest first:
call Strip_Batch.bat %%i !Stripped_Name!
and second (better, works also for parameter with spaces):
call Strip_Batch.bat "%%i" "!Stripped_Name!"

Related

Why deleting a substring in a string doesn't work. Batch

#echo off
#chcp 65001
setlocal enableextensions enabledelayedexpansion
set test=qwert
goto start
:IsStrInStrFunc
setlocal
call set check=%%1:%2=%
echo %check%
endlocal
exit /b
:start
call :IsStrInStrFunc %test%, q
pause
The "check" variable must contain "wert". What's wrong?.......
if you want to set %check% to be "wert"
set check=%%1:%2=%
should be
set check=%test:~1%
For more info check command help set in Command Prompt
Perhaps this example will assist you:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Delims==" %%G In ('"(Set _cp) 2> NUL"') Do Set "%%G="
For /F Tokens^=* %%G In ('"%SystemRoot%\System32\chcp.com"'
) Do For %%H In (%%G) Do Set "_cp=%%~nH"
If Not %_cp% Equ 65001 (Set "_cpc=TRUE"
"%SystemRoot%\System32\chcp.com" 65001 >NUL)
Set "test=qwert"
GoTo Start
:IsStrInStrFunc
Set "check=%~1"
Echo Before: %check%
SetLocal EnabledelayedExpansion
Set "check=!check:%~2=!"
EndLocal & Echo After: %check%
Exit /B
:Start
Call :IsStrInStrFunc "%test%" "q"
Pause
If Defined _cpc "%SystemRoot%\System32\chcp.com" %_cp% >NUL
GoTo :EOF
To do substring substitution on a variable, you need the variablename, not its value (see set /?), so your parameter in the call can't be %test% (which would pass the string quert), but must be test.
And as you are using delayed expansion anyway, why not using it?
#echo off
#chcp 65001
setlocal enableextensions enabledelayedexpansion
set "test=qwert"
goto start
:IsStrInStrFunc
setlocal
REM call set "check=%%%~1:%~2=%%"
set "check=!%~1:%~2=!"
echo %check%
endlocal
exit /b
:start
call :IsStrInStrFunc test q
PS: you don't need the ~ chars with your simple example, but they don't disturb either. Imagine you want to replace a string, you can simply do that with call :IsStrInStrFunc test "a string" (that's where the ~ are necessary. Good practice to include them anyway (just in case))

Batch - How to echo exclamation mark inside string passed as parameter to subroutine?

I have the following script:
#ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
SET /A countArgs=1
FOR %%p in (%pathListToCheck%) DO (
IF NOT EXIST %%p (
CALL :error "!countArgs!. Argument -> bla!"
EXIT /B 1
)
SET /A countArgs+=1
)
:error
ECHO ERROR
set x=%~1
ECHO !x!
EXIT /B 0
Unfortunately the exclamation mark does not get echod. I also tried to escape it like ^! and ^^! but it doesn't work.
I use delayed expension here to make the greater-then sign (>) work. If i would try to ECHO the parameter directly (ECHO %~1) it would fail. For details see my previous question
How can fix this?
I appreciate your help...
If you escape the exclamation mark and disable delayed expansion inside the function, it works (although it removes the "delayed" alternative - which you didn't like anyway)
#echo off
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
SET /A countArgs=2
CALL :error "!countArgs!. Argument -> bla^!"
EXIT /B 1
:error
setlocal disabledelayedexpansion
for /f "delims=" %%a in ("%~1") do echo for: %%a
echo quoted: "%~1"
endlocal
EXIT /B 0
You didn't read/understand Stephans summary in his answer.
setlocal enabledelayedexpansion is the cause of the vanished exclamation marks.
There is no reason to use it in your present code.
If you want to echo <|>& without qoutes you have to escape those. That can be done by code.
:: Q:\Test\2018\05\19\SO_50419709.cmd
#Echo off
SetLocal EnableExtensions DisableDelayedExpansion
SET /A countArgs=1
set "pathlisttocheck=%userprofile%,x:\x\x\"
FOR %%p in (%pathListToCheck%) DO (
IF NOT EXIST %%p (
CALL :error "%%countArgs%%. Argument -> bla! %%~p"
EXIT /B 1
)
SET /A countArgs+=1
)
EXIT /B 1
:error
ECHO ERROR
set "x=%~1"
set "x=%x:>=^>%"
ECHO %x%
EXIT /B 0
Sample output:
> Q:\Test\2018\05\19\SO_50419709.cmd
ERROR
2. Argument -> bla! x:\x\x\

Setting an environment variable with delayed expansion enabled

I have the following script that should set an environment variable %NUMBER%:
#ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
SET processed=0
IF "%~1"=="latest" (
CALL :LATEST_BUILD_NUMBER %~2
ECHO "->%build_number% RETURNS NO DATA"
ECHO "->!build_number! GIVES THE BUILD NUMBER BACK"
CALL :SET_ENVIRONMENT_VARIABLE !build_number!
SET processed=1
)
:END
ENDLOCAL
ECHO ON
#EXIT /B 0
:SET_ENVIRONMENT_VARIABLE
ECHO SET "NUMBER=%~1"
SET "NUMBER=%~1"
#EXIT /B 0
:LATEST_BUILD_NUMBER
REM CALCULATE THE BUILDNUMBER, NOW JUST SET IT
set build_number=589
EXIT /B 0
When I do run this code in a command prompt window, and do an echo of the NUMBER variable, it is not set in console window.
d:\> ECHO %NUMBER%
%NUMBER%
How should I do this correctly?
Each setlocal creates a new variable scope.
This scope will be destroyed with endlocal or implicit by exiting the batch file.
You have to safe your variables over the scope lifetime (often called endlocal barrier).
In a called function it's not possible to ENDLOCAL an outer SETLOCAL (not impossible, but only with advanced technics).
So you have to modify your code.
#ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion
SET processed=0
SET build_number=0
IF "%~1"=="latest" (
CALL :LATEST_BUILD_NUMBER %~2
ECHO -^>%build_number% RETURNS NO DATA
ECHO -^>!build_number! GIVES THE BUILD NUMBER BACK
REM *** CALL :SET_ENVIRONMENT_VARIABLE !build_number!
SET processed=1
)
:END
(
ENDLOCAL
set "number=%build_number%"
EXIT /B 0
)
...
The trick is to build an ENDLOCAL-Block with parenthesis, as the percent expansion is evaluated when the block is parsed, so the value will be available after the ENDLOCAL is executed.

Passing exclamation marks as parameters in batch subroutine call

Thanks to this community I have finally learned how to escape exlamation marks for immediate use in a batch delayedExpansion block.
(use two escape carets not just one, awesome)
But I can't seem to find or figure out how to pass the contents of a variable containing an exclamation mark as parameter to a batch subroutine.
example:
#echo off
setLocal EnableDelayedExpansion
set variable=Hello^^!
echo "!variable!"
call :subroutine "!variable:^^!=^^!!"
pause
exit
:subroutine
echo "%~1"
exit/b
Output:
"Hello!"
"Hello"
Press any key to continue . . .
I want the second "Hello" to include an exclamation mark.
I have tried various permutations of substring replacement on line 5 to no avail.
help
You need a different way for the variable replacing, and much more carets.
#echo off
setLocal EnableDelayedExpansion
set variable=Hello^^!
echo "!variable!"
call :subroutine %variable:!=^^^^^^^^^^!%
exit /b
:subroutine
echo %~1
exit /b
Or with quotes:
call :subroutine "%variable:!=^^^!%"
In your function you need to expand %1 without any quotes, as the number of carets are always odd in a CALL parameter.
But at all it's a bad idea to try such things.
I agree with Aacini, that you should use pass by reference instead.
This is the only way to handle any possible content.
#echo off
setLocal EnableDelayedExpansion
set variable=Hello^^!
echo "!variable!"
call :subroutine variable
exit /b
:subroutine
echo !%1!
exit /b
Maybe the problem is not how to pass the data to the subroutine, but how to get the data inside it
#echo off
setlocal enabledelayedexpansion
set "var=Hello^!"
setlocal disabledelayedexpansion
echo %var%
call :echo1 %var%
call :echo2 var
endlocal
setlocal enabledelayedexpansion
echo !var!
call :echo1 !var!
call :echo2 var
endlocal
endlocal
exit /b
:echo1
setlocal disabledelayedexpansion
echo %~1
endlocal
goto :eof
:echo2
setlocal enabledelayedexpansion
echo !%~1!
endlocal
goto :eof

return value from batch script

I am calling batch script from vbscript.
In the batch script, based on condition I want to return custom exit code.
#echo off
setlocal ENABLEDELAYEDEXPANSION`
for /f "usebackq" %%i in (`"%1"\fciv.exe" -md5 %2"`) do set md5_1=%%i
for /f "usebackq" %%i in (`"%1"\fciv.exe" -md5 %3"`) do set md5_2=%%i
if "!md5_1!" == "!md5_2!" (
set md5_1=
set md5_2=
exit 0
) else (
set md5_1=
set md5_2=
exit 1
)
endlocal
I am getting value 0 for both of the conditions.
can anybody help me?
The batch processor (cmd) will actually retain the errorlevel of the last call.
To use this feature, do not call endlocal at the end of the script,
this is called implicitly anywayMSDN
Besides, always use exit /b inside scripts, as the normal exit call will also exit the current batch processor instance
Both your commands look to have mismatched quotes and can fail with long names. Try this
You aren't used delayed expansion and nulling the variables is pointless when a setlocal has been issued.
Usebackq is not needed.
Finally it's bad practice to use %%i because it looks so much like %%l and %%1
Microsoft uses it in examples, I know.
#echo off
setlocal
for /f %%a in ('"%~1\fciv.exe" -md5 "%~2"') do set md5_1=%%a
for /f %%a in ('"%~1\fciv.exe" -md5 "%~3"') do set md5_2=%%a
if "%md5_1%"=="%md5_2%" (exit /b 0) else (exit /b 1 )
endlocal

Resources