call expands variables / parameters differently with double percent signs

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
pieh-ejdsch
Posts: 203
Joined: 04 Mar 2014 11:14
Location: germany

call expands variables / parameters differently with double percent signs

#1 Post by pieh-ejdsch » 03 Nov 2018 08:16

Hello Reader,

The question was asked about the possibility to pass more than 10 parameters in one line.
Do not be surprised %0 is also a parameter.
When reading from all parameters, which are passed to the batch file, I am not quite satisfied with some solutions.
For more than 10 parameters, you must use shift.
It is also clear that a command line can only read a maximum of 10 parameters.
As we know, Shift does not do anything in this case.
Therefore, each parameter is passed to a variable and goto: Read ... is used.

Variable creation is often used:

Code: Select all

call set X=%%variable%%
I have already used:

Code: Select all

call :sub %%variable%%
This variable is then used in :sub as a parameter.
The parameters can also be passed on like this:

Code: Select all

call :Sub %%1 %%*
The variables and parameters are NOT expanded during reading.
BUT the line to be called is completely included in the parsing, this can be seen in the following test.
Thus changes take place only during the call in the :Sub.

Now I had wanted to test something and came across a THING.

First, create a batch that reads in the parameters and makes them available as variables.
Then I have created a batch, which starts another batch with parameters - so far.

Code: Select all

@ echo off
if not "%~1" == "" goto %1
setlocal
set prompt=$g$s
rem pushD will go out
if "%cd%\" neq "%~dp0" set "CD=%~dp0"
set "Batch=moreparam"
call :make2
@ for /f %%i in  ('findstr ":test[0-9][0-9]*" "%~nx0"') do @ ( echo(
  echo rem %%i :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  cmd /c ""%~f0" %%i"
  call echo errorlevel == %%errorlevel%%
  echo END %%i -----------------------------------------------------------
)
pause
exit /b

:test0
set ^"ALL="" B "C" Hello! "%%PATH%%" F G "Operators: &()[]{}^=;!'+,`~<>|" I J K !PATHEXT! M N"
set in=14
echo rem call in == %in% Param
echo on
call %batch% %%ALL%%
exit /b

:test1
set in=14
echo rem in == %in% Param
echo on
%batch%  "" B "C" Hello! "%%PATH%%" F G "Operators: &()[]{}^=;!'+,`~<>|" I J K !PATHEXT! M N
exit /b

:test2
set ^"ALL=1 a^^^^; bb c%%%% d%%%% e%% f%% "g^^" ^^^^^; !i-test! %%j-test%% k^^^^^^^^; l^^"
set in=13
echo  rem call in == %in% Param
echo on
call %batch% %%ALL%%
exit /b

:test3
set in=13
echo rem in == %in% Param
echo on
%batch% 1 a^^^^; b c%%%% d%%%% e%% f%% "g^^" ^^^^^; !i-test! %%j-test%% k^^^^^^^^; l^^;
exit /b

:test4
set in=13
echo rem in %in% Param
echo on
%batch% 1 a^^^^; "b;" c%%%% d%%%% e%% f%% "g^^" ^^^^^; !i-test! ^^%%j-test^^^%% k^^^^^^^^; l^^
exit /b

:test5
set in=7
echo rem in %in% Param
echo on
%batch% a b%% "c^^" !d! ^%%e^%% f^^^^^^^^ g^^
exit /b

:test6
set in=7
echo rem in %in% Param
echo on
%batch% a b%% "cc^^" !d! ^%%e^%% f^^^^^^^^ g^^
exit /b

:test7
set in=7
echo rem in %in% Param
echo on
%batch% a b%% "ccc^^" !d! ^%%e^%% f^^^^^^^^ g^^
exit /b

:test8
set in=6
echo rem in %in% Param (other^)
echo on
%batch% 1 2%% "3^^" !4! ^%%5^%% 6^^
exit /b

:test9 
set in=9
echo rem in %in% Param
echo on
%batch% "" 1 2%% '3^^' ^%%4 ^%%5^%% 6^^^^^^^^ 7^^^^ 8^^
exit /b

:test10
set in=4
echo rem in %in% Param 
echo on
%batch% "a" %b% c^^^^ d^^
exit /b

:make2
@ for /f "delims=[]" %%i in ('find /n " x8l2n63 " ^< "%~f0"') do more +%%i "%~f0" | > "%batch%.cmd" find /v "" & exit /b
@ echo on
@ setlocal
@ set prompt=$g$g$s
 rem Command: %0 %*

call :setParam %%*

@ set /a out = maxCount -100
 rem %0  Param == %out% 
@ for /f "delims=#= tokens=1*" %%i in ('2^>nul set #') do @ if %%i leq %maxCount% echo %%i= '%%j' 
@ set #END=END
set #
@ if %in% neq %out% exit /b 1
@ exit /b

:setParam
rem sub = %0
@ echo off
set /a pn =100, p9 =p0 +9
shift
:setCountParam
@ for /L %%L in (0 1 9) do set/a p%%L =%%L +pn +1
set #%p0%=%0


set #%p1%=%1


set #%p2%=%2


set #%p3%=%3


set #%p4%=%4


set #%p5%=%5


set #%p6%=%6


set #%p7%=%7


set #%p8%=%8


set #%p9%=%9


if defined #%p9% (
  @ for /L %%L in (0 1 9) do shift
  set /a pn +=10
  set MaxCount=%p9%
  goto :setCountParam
)
for /L %%L in (%p0% 1 %p8%) do if defined #%%L set MaxCount=%%L
echo on
 rem %*
@ exit /b
A few tests with percent and exclamation marks and so on ...
Then with a double circumflex final.
The parameters are passed into the :Sub but with circumflex at the end these parameters expand to a rat tail.
some results

Code: Select all

rem :test0 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
rem call in == 14 Param

> call moreparam %ALL% 

>> rem Command: moreparam "" B "C" Hello! "%PATH%" F G "Operators: &()[]{}^=;!'+,`~<>|" I J K !PATHEXT! M N 

>> call :setParam %* 

>> rem sub = :setParam 

>> rem "" B "C" Hello! "%PATH%" F G "Operators: &()[]{}^=;!'+,`~<>|" I J K !PATHEXT! M N 

>> rem moreparam  Param == 14  
101= '""' 
102= 'B' 
103= '"C"' 
104= 'Hello!' 
105= '"%PATH%"' 
106= 'F' 
107= 'G' 
108= '"Operators: &()[]{}^=;!'+,`~<>|"' 
109= 'I' 
110= 'J' 
111= 'K' 
112= '!PATHEXT!' 
113= 'M' 
114= 'N' 

>> set # 
#101=""
#102=B
#103="C"
#104=Hello!
#105="%PATH%"
#106=F
#107=G
#108="Operators: &()[]{}^=;!'+,`~<>|"
#109=I
#110=J
#111=K
#112=!PATHEXT!
#113=M
#114=N
#END=END

> exit /b 
errorlevel == 0
END :test0 -----------------------------------------------------------

rem :test1 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
rem in == 14 Param

> moreparam  "" B "C" Hello! "%PATH%" F G "Operators: &()[]{}^=;!'+,`~<>|" I J K !PATHEXT! M N 

>> rem Command: moreparam "" B "C" Hello! "%PATH%" F G "Operators: &()[]{}^=;!'+,`~<>|" I J K !PATHEXT! M N 

>> call :setParam %* 

>> rem sub = :setParam 

>> rem "" B "C" Hello! "%PATH%" F G "Operators: &()[]{}^=;!'+,`~<>|" I J K !PATHEXT! M N 

>> rem moreparam  Param == 14  
101= '""' 
102= 'B' 
103= '"C"' 
104= 'Hello!' 
105= '"%PATH%"' 
106= 'F' 
107= 'G' 
108= '"Operators: &()[]{}^=;!'+,`~<>|"' 
109= 'I' 
110= 'J' 
111= 'K' 
112= '!PATHEXT!' 
113= 'M' 
114= 'N' 

>> set # 
#101=""
#102=B
#103="C"
#104=Hello!
#105="%PATH%"
#106=F
#107=G
#108="Operators: &()[]{}^=;!'+,`~<>|"
#109=I
#110=J
#111=K
#112=!PATHEXT!
#113=M
#114=N
#END=END
errorlevel == 0
END :test1 -----------------------------------------------------------

...
...

rem :test7 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
rem in 7 Param

> moreparam a b% "ccc^^" !d! %e% f^^^^ g^ 

>> rem Command: moreparam a b% "ccc^^" !d! %e% f^^^^ g^ 

>> call :setParam %* 

>> rem sub = :setParam 

>> rem a b% "ccc^^" !d! %e% f^^ gd! %e% f^^ getParam a b% "ccc^^" !d! %e% f^^ gcc^" !d! %e% f^^^^ g^ 

>> rem moreparam  Param == 17  
101= 'a' 
102= 'b%' 
103= '"ccc^^"' 
104= '!d!' 
105= '%e%' 
106= 'f^' 
107= 'gd!' 
108= '%e%' 
109= 'f^' 
110= 'getParam' 
111= 'a' 
112= 'b%' 
113= '"ccc^^"' 
114= '!d!' 
115= '%e%' 
116= 'f^' 
117= 'gcc" !d! %e% f^^ g' 

>> set # 
#101=a
#102=b%
#103="ccc^^"
#104=!d!
#105=%e%
#106=f^
#107=gd!
#108=%e%
#109=f^
#110=getParam
#111=a
#112=b%
#113="ccc^^"
#114=!d!
#115=%e%
#116=f^
#117=gcc" !d! %e% f^^ g

#END=END
errorlevel == 1
END :test7 -----------------------------------------------------------

rem :test8 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
rem in 6 Param (other)

> moreparam 1 2% "3^^" !4! %5% 6^ 

>> rem Command: moreparam 1 2% "3^^" !4! %5% 6^ 

>> call :setParam %* 

>> rem sub = :setParam 

>> rem 1 2% "3^^" !4! %5% 6^" !4! %5% 6^ 

>> rem moreparam  Param == 6  
101= '1' 
102= '2%' 
103= '"3^^"' 
104= '!4!' 
105= '%5%' 
106= '6" !4! %5% 6' 

>> set # 
#101=1
#102=2%
#103="3^^"
#104=!4!
#105=%5%
#106=6" !4! %5% 6

#END=END
errorlevel == 0
END :test8 -----------------------------------------------------------

rem :test9 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
rem in 9 Param

> moreparam "" 1 2% '3^' %4 %5% 6^^^^ 7^^ 8^ 

>> rem Command: moreparam "" 1 2% '3^' %4 %5% 6^^^^ 7^^ 8^ 

>> call :setParam %* 

>> rem sub = :setParam 

>> rem "" 1 2% '3' %4 %5% 6^^ 7^ 8^ 7^ 82% '3' %4 %5% 6^^ 7^ 8 %4 %5% 6^^ 7^ 8aram "" 1 2% '3' %4 %5% 6^^ 7^ 8% 6^^ 7^ 8" 1 2% '3^' %4 %5% 6^^^^ 7^^ 8^ 

>> rem moreparam  Param == 34  
101= '""' 
102= '1' 
103= '2%' 
104= ''3'' 
105= '%4' 
106= '%5%' 
107= '6^' 
108= '7' 
109= '8' 
110= '7' 
111= '82%' 
112= ''3'' 
113= '%4' 
114= '%5%' 
115= '6^' 
116= '7' 
117= '8' 
118= '%4' 
119= '%5%' 
120= '6^' 
121= '7' 
122= '8aram' 
123= '""' 
124= '1' 
125= '2%' 
126= ''3'' 
127= '%4' 
128= '%5%' 
129= '6^' 
130= '7' 
131= '8%' 
132= '6^' 
133= '7' 
134= '8" 1 2% '3^' %4 %5% 6^^^^ 7^^ 8^' 

>> set # 
#101=""
#102=1
#103=2%
#104='3'
#105=%4
#106=%5%
#107=6^
#108=7

#109=8

#110=7

#111=82%
#112='3'
#113=%4
#114=%5%
#115=6^
#116=7

#117=8
#118=%4
#119=%5%
#120=6^
#121=7

#122=8aram
#123=""
#124=1
#125=2%
#126='3'
#127=%4
#128=%5%
#129=6^
#130=7

#131=8%
#132=6^
#133=7

#134=8" 1 2% '3^' %4 %5% 6^^^^ 7^^ 8^
#END=END
errorlevel == 1
END :test9 -----------------------------------------------------------

rem :test10 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
rem in 4 Param 

> moreparam "a"  c^^ d^ 

>> rem Command: moreparam "a"  c^^ d^ 

>> call :setParam %* 
errorlevel == 255
END :test10 -----------------------------------------------------------
Drcken Sie eine beliebige Taste . . . 


This does not happen with a terminating semicolon or comma

If the length is indefinite, the batch will go down.
It seems like the parameters are interleaved (and sometimes not ending).

Unfortunately, I can not say why this happens, but there is a rule according to which it is multiplied piece by piece.
Unfortunately, I have not yet discovered this.
Sometimes, there are four or two characters of the calling line, as this peak is likely to expand, to make these characters shorter again and again.

When the line of the call is extended or truncated, the behavior of the number of parameters changes or becomes so large that it fails.

By the way - The same behavior can also be observed with

Code: Select all

call set x=%%variable%%
.

Phil

jeb
Expert
Posts: 917
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: call expands variables / parameters differently with double percent signs

#2 Post by jeb » 04 Nov 2018 13:51

Hi pieh-ejdsch,
pieh-ejdsch wrote:
03 Nov 2018 08:16
Then with a double circumflex final.
The parameters are passed into the :Sub but with circumflex at the end these parameters expand to a rat tail.
The caret/circumflex will be doubled always by a CALL command, normally this isn't visible, as the doubled carets are used as escape characters and they will be removed again.
But if a quote is before a caret the escaping will not be executed, so the doublling will be visible.

Code: Select all

call echo two carets ^^ ...
call echo "two carets ^^ ...
CALL call echo "two carets ^^ ...
Output wrote:two carets ^ ...
"two carets ^^^^ ...
"two carets ^^^^^^^^ ...
If there is a single unescaped caret at the end of a line, it is used as multiline character, but in the case of CALL there isn't any next line, that seems to be the cause for the crash.

Code: Select all

call echo This takes the next line-^
Line2

set "var=With quote, it works^"
call echo " %%var%%

set "var=This crashes ^"
call echo %%var%%
echo Never reached

Post Reply