Access complex parameters

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
jeb
Expert
Posts: 1042
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Access complex parameters

#1 Post by jeb » 13 Apr 2011 17:03

Is it possible to access the complete content of parameters, if they are contain a <CR> or <LF> characters?

This is simliar to the problem of returning any content from a bacth function new functions: :chr, :asc, :asciiMap.

At first, I show a small sample:

myBatch.bat

Code: Select all

@echo off
echo 1:%*
(
echo 2:%*
)

Calling it with

Code: Select all

myBatch hello^

you
The empty line is neccessary to add the linefeed character

-----Output---- wrote:1:hello
2:hello
The command "you" is unknown ...


As you can see it could be a bit tricky.

Currently, I can't see any solution, but perhaps someone has a good idea to solve this.


jeb

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Access complex parameters

#2 Post by dbenham » 13 Apr 2011 22:29

Interesting...

I tried the following:

caller.bat

Code: Select all

@echo off
setlocal enabledelayedexpansion
set var=hello^

you
set var
call myBatch "!var!"


results:

Code: Select all

>caller
var=hello
you
1:"hello
2:"hello

>


The error is gone, but what happened to "you"? I don't suppose your secure parameter handling would find it?

Dave

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

Re: Access complex parameters

#3 Post by jeb » 14 Apr 2011 05:17

In the first moment I thought, obviously why it doesn't work.

I changed it to the correct form (^%LF%%LF%) and it worked as expected, then I changed it to the simplest form (removing the call).
And it worked completly unexpected :o

Caller.bat

Code: Select all

@echo off
cls
setlocal EnableDelayedExpansion
set "caret=^"
set lf=^


set "var1=hello!caret!!lf!!lf!ECHO TWO"
set var2=hello^

you
echo ---- call Test1 ----
call myBatch %%var1%%
echo ---- direct Test2 ----
myBatch !var2!


myBatch.bat

Code: Select all

@echo off
set "param=%*"
if !param!==!var2! (echo OK) ELSE (echo NOT OK)

echo 1:%*
(
echo 2:%*
)


---- call Test1 ----
NOT OK
1:hello
2:hello
TWO
---- direct Test2 ----
OK
1:hello
you
2:hello
you


The result of test1 is the expected result.
I create the LF in the second run of the script parser, as the line is two times parsed because of the call.
Else the linefeed removes the rest of the line.

What the hell, the test2 seems to work, but this can't be, why the %1 can expand to a linefeed without removing the rest of the line :?:

This morning, I was totally confused.

I supposed there must be a new mechanism, a new ...
Ok it's new, but it's so simply :(

jeb

aGerman
Expert
Posts: 4654
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Access complex parameters

#4 Post by aGerman » 17 Apr 2011 09:09

Hello jeb,

seems that !var2! does not expand in Caller.bat.

I changed myBatch.bat

Code: Select all

@echo off
prompt $g
echo on
rem %*
@echo off
set "param=%*"
if !param!==!var2! (echo OK) ELSE (echo NOT OK)

echo 1:%*
(
echo 2:%*
)

The result is

Code: Select all

---- call Test1 ----

>rem hello
NOT OK
1:hello
2:hello
TWO
---- direct Test2 ----

>rem !var2!
OK
1:hello
you
2:hello
you

Regards
aGerman

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Access complex parameters

#5 Post by dbenham » 17 Apr 2011 23:07

Using aGerman's myBatch:

caller:

Code: Select all

@echo off
cls
setlocal enableDelayedExpansion
set var1=hello^

you
echo ---- Test1 ----
echo We have seen this already.
call myBatch !var1!
echo:

echo ---- Test2 ----
echo This is new to me
call (this is totally ignored!?)&echo What is going on?
echo:

echo ---- Test3 ----
echo Ignored call has no effect on called myBatch
call (makes no apparent difference when call)&call myBatch !var1!
echo:

echo ---- Test4 ----
echo But ignored call breaks direct myBatch.
call (but direct now fails)&myBatch !var1!

echo Never gets here


result:

Code: Select all

---- Test1 ----
We have seen this already.

>rem hello
NOT OK
1:hello
2:hello

---- Test2 ----
This is new to me
What is going on?

---- Test3 ----
Ignored call has no effect on called myBatch

>rem hello
NOT OK
1:hello
2:hello

---- Test4 ----
But ignored call breaks direct myBatch.

>rem hello
NOT OK
1:hello
2:hello
'you' is not recognized as an internal or external command,
operable program or batch file.


None of this makes any sense to me

dbenham

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

Re: Access complex parameters

#6 Post by jeb » 18 Apr 2011 04:46

Nice to see the input.

First, the observations of dbenham.

The **call** behaviour is "normal", as call fails complete if there is a block, & or | in the second run of parsing.

Code: Select all

call echo 1: Hello & echo 1: you
call echo 2: Hello ^& echo 2: you
call ( echo 3: Hello ) & echo 3: you


Output:

Code: Select all

1: Hello
1: you
3: you


As the & simply splits the line in the examples 1 and 3 into two seperate commands.

dbenham wrote:echo ---- Test4 ----
echo But ignored call breaks direct myBatch.
call (but direct now fails)&myBatch !var1!

That is the normal behaviour for batch files, batch files have to be called (to return), else it works like a "goto"

@aGerman:
aGerman wrote:seems that !var2! does not expand in Caller.bat.

Yes, that's the simple cause, why it works.
This behaviour is new for me, but not so sensational as I first think.

But I found another curious behaviour at ths point.

Caller.bat

Code: Select all

@echo off
setlocal EnableDelayedExpansion
set lf=^


set var2=hello^

echo you
echo ---- direct Test2 ----
echo on
for %%A in (111 222 333) do (
myBatch !var2!%%A
)


I modified the myBatch.bat a bit, at the **REM**, I surround it with parenthesis, so I can see the complete multiline output of %*

Code: Select all

echo on
(
rem %* #
)
@echo off


**Output**

Code: Select all

---- direct Test2 ----

C:\temp>for %A in (111 222 333) do (myBatch !var2!%A )

C:\temp>(myBatch !var2!111 )
NOT OK

C:\temp>(
rem hello
 echo you111 #
)
you111 #
1:hello
2:hello
you111

C:\temp>(myBatch !var2!222 )
NOT OK

C:\temp>(rem !var2!222 # )
1:!var2!222
2:!var2!222

C:\temp>(myBatch !var2!333 )
NOT OK

C:\temp>(rem !var2!333 # )
1:!var2!333
2:!var2!333


As you can see, in the first call of myBatch.bat the parameters are 'hello<LF>you111',
but for the second and third loop they are '!var2!222' and '!var2!333'. :?:

There are always new things to explain. :)

jeb

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Access complex parameters

#7 Post by dbenham » 18 Apr 2011 06:40

Thanks for the info Jeb - You got the 1st point (question) of my last post.

But I think you missed the 2nd.

After adding the # to the REM in myBatch:

caller1:

Code: Select all


@echo off
setlocal enableDelayedExpansion
set var1=hello^

you

myBatch !var1!


caller1 result:

Code: Select all

>rem !var1! #
OK
1:hello
you
2:hello
you


caller2:

Code: Select all


@echo off
setlocal enableDelayedExpansion
set var1=hello^

you

call (junk)&myBatch !var1!


caller2 result:

Code: Select all

>rem hello
NOT OK
1:hello
2:hello
'you' is not recognized as an internal or external command,
operable program or batch file.


With caller1 !var1! expands within myBatch
With caller2 !var1! expands before myBatch


With regard to behaviour in:

Code: Select all

for %%A in (111 222 333) do (
myBatch !var2!%%A
)


Would'nt your result be expected? Since there is no call, the setlocal batch scope should be gone by the time you get your 2nd iteration. In other words I would expect an implicit endlocal by the time the 1st iteration is complete.

Dave

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Access complex parameters

#8 Post by dbenham » 18 Apr 2011 08:47

further illustrating effect of for loop with the implicit endlocal

parent1.bat

Code: Select all

@echo off
setlocal enableDelayedExpansion
set var1=parent1
call parent2
echo after parent2: !var1!


parent2.bat

Code: Select all

@echo off
setlocal enableDelayedExpansion
set var1=parent2
call parent3
echo after parent3: !var1!


parent3.bat

Code: Select all

@echo off
setlocal enableDelayedExpansion
set var1=parent3
call caller
echo after caller: !var1!


caller.bat

Code: Select all

@echo off
cls
setlocal enableDelayedExpansion
set var1=caller
for /l %%n in (1,1,3) do (
  echo iteration %%n -------------------
  myBatch !var1!
  echo:
)


myBatch.bat

Code: Select all

echo on
rem %* #
@echo off
set "param=%*"
echo 1:%*
(
echo 2:!param!
)


result of parent1:

Code: Select all

iteration 1 -------------------

P:\>rem caller #
1:caller
2:caller

iteration 2 -------------------

P:\>rem parent3 #
1:parent3
2:parent3

iteration 3 -------------------

P:\>rem parent2 #
1:parent2
2:parent2

after parent2: parent1


Note that Parent2 and Parent3 never returned!

-----------------------------------------------------------
Contrast above with results without for loop

parent.bat:

Code: Select all

@echo off
call caller2
echo I expect this to print


caller2.bat:

Code: Select all

@echo off
cls
setlocal enableDelayedExpansion
set var1=caller
myBatch !var1!
echo don't expect this to print


results of parent:

Code: Select all

P:\>rem !var1! #
1:caller
2:caller
I expect this to print


So for me the for loop has 2 interesting effects:
1) causes !var1! to be expanded before entering myBatch
2) breaks the CALL of the parent

amel27
Expert
Posts: 177
Joined: 04 Jun 2010 20:05
Location: Russia

Re: Access complex parameters

#9 Post by amel27 » 04 May 2011 03:03

Hi, All!
Nice thread
dbenham wrote:2) breaks the CALL of the parent
running nested BAT without CALL terminate current BAT thread

Code: Select all

@echo off
SetLocal EnableDelayedExpansion

set var1=TEST

myBatch !var1!
echo This line not typed
If your have several nested calls, each BAT running without CALL terminate last thread. In your sample:

%%n=1: terminate caller
%%n=2: terminate parent3
%%n=3: terminate parent2

As result, parent1 only finished successfully

dbenham wrote:1) causes !var1! to be expanded before entering myBatch
with terminating BAT thread,environment popped,
therefore !var1! expansion depends on environment of current active BAT thread

dbenham wrote:With caller1 !var1! expands within myBatch
With caller2 !var1! expands before myBatch
this code:

Code: Select all

call (junk)&myBatch !var1!
work like this:

Code: Select all

(
call (junk)
myBatch !var1!
)
first nested BAT running w/o CALL parsed and expanded in current environment, all others in environments of nested threads (if exist), otherwise default environment is applied (with DisableDelayedExpansion), if parentheses missed, accessible nested depth is less on unit

amel27
Expert
Posts: 177
Joined: 04 Jun 2010 20:05
Location: Russia

Re: Access complex parameters

#10 Post by amel27 » 04 May 2011 21:15

jeb wrote:As you can see, in the first call of myBatch.bat the parameters are 'hello<LF>you111',
but for the second and third loop they are '!var2!222' and '!var2!333'. :?:
as explain above, at the end of each myBatch ENDLOCAL executed, for full expanded Caller must be start via

Code: Select all

CMD /V:ON /C Caller

and there are some new things,
myBatch code:

Code: Select all

SETLOCAL DisableDelayedExpansion

echo 2:%*

ENDLOCAL

echo 3:!var!
echo 4:%*
Caller code:

Code: Select all

@echo off
set var=TST_!var!
SETLOCAL EnableDelayedExpansion

echo 1:!var!
myBatch !var!
output:

Code: Select all

1:TST_!var!
2:!var!
3:TST_!var!
4:TST_!var!

apparently from this example, last command line not expanded
...but if first token contain exclamations, whole line expanded! :!:
Caller code:

Code: Select all

@echo off
set var=TST_!var!
SETLOCAL EnableDelayedExpansion

echo 1:!var!
myBatch! !var!
result:

Code: Select all

1:TST_!var!
2:TST_!var!
3:TST_!var!
4:TST_TST_!var!

amel27
Expert
Posts: 177
Joined: 04 Jun 2010 20:05
Location: Russia

Re: Access complex parameters

#11 Post by amel27 » 05 May 2011 03:56

jeb wrote:Is it possible to access the complete content of parameters, if they are contain a <CR> or <LF> characters?
In my tests about %* substitution all <CR> trimmed and <LF> replace to <CRLF>,
therefore command line splitted to lines with leading and trailing space.

Caller code:

Code: Select all

@Echo Off
SetLocal EnableDelayedExpansion
for /f %%a in ('copy /Z "%~f0" nul') Do set "cr=%%a"
set lf=^


>myBatch.tmp myBatch! #!cr!_hello_!lf!_you_!lf!!cr!^

_
myBatch code:

Code: Select all

@Echo On
@SetLocal DisableDelayedExpansion

(@exit/b
%*
)
myBatch.tmp (leading spaces removed by forum engine):

Code: Select all

C:\_1\01>(
 
 #_hello_
 _you_
 _
)

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

Re: Access complex parameters

#12 Post by jeb » 06 May 2011 05:36

Hi amel27,

nice to see so many people explore this topic. :D

The expansion differences of

Code: Select all

myBatch! !var!
myBatch !var!

This is really new to me, and I can't understand the reason, I assume that in the second case it is simply a bug, that it doesn't expands.

amel27 wrote:In my tests about %* substitution all <CR> trimmed and <LF> replace to <CRLF>,
therefore command line splitted to lines with leading and trailing space.

Your conclusion is not correct, as the space is inserted by the echo on mechanism, but it doesn't exists in the parameter.

Code: Select all

set lf=^


set "var=Content^^^^^^!lf!!lf!^^!lf!!lf!Line2"
call myBatch %%var%%


myBatch

Code: Select all

@echo off
echo on
(
 @goto :echoEnd
 rem #%*#
)
:echoEnd
@echo off
echo ---
echo %*
echo ---


Outputs

Code: Select all

C:\temp>(

 rem #Content^
 Line2#
)
---
Content
Line2
---


jeb

amel27
Expert
Posts: 177
Joined: 04 Jun 2010 20:05
Location: Russia

Re: Access complex parameters

#13 Post by amel27 » 07 May 2011 08:44

Wow! I see, You have found a solution of a problem? :wink:
Brilliant, jeb! :D

Code: Select all

@Echo Off
SETLOCAL EnableDelayedExpansion
set lf=^


set "var=Content!lf!Line2!lf!Line3"
call:EscLF var 2
call myBatch %%var%%

exit/b

:EscLF %varName% %cnt%
::--------------------
for /l %%i in (1,1,%~2) do (set "%~1=!%~1:^=^^!"
set %~1=!%~1:^

=^^^

^

!)
GoTo:EOF
myBatch:

Code: Select all

@echo off
set $v=%*
echo !$v!
result:

Code: Select all

Content
Line2
Line3

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

Re: Access complex parameters

#14 Post by jeb » 08 May 2011 06:39

amel27 wrote:Wow! I see, You have found a solution of a problem? :wink:
Brilliant, jeb! :D


Sorry, I'm not so brilliant, as it isn't the solution :?
It is a way to create a parameter, so it creates a single LF after the expansion of %1.

But in reallity the parameter contains three characters "^<LineFeed><LineFeed>".

And currently I'm not able to access these characters :(

jeb

amel27
Expert
Posts: 177
Joined: 04 Jun 2010 20:05
Location: Russia

Re: Access complex parameters

#15 Post by amel27 » 08 May 2011 09:05

jeb wrote:It is a way to create a parameter
Yes, this is a way for pure transfer variable to internal procedure or nested BAT file via CALL. For this purpose we should prepare parameter correctly and we can automated this task, as above example show. But if BAT file start from third party external application via CMD.EXE, we can simply access full command line via !CMDCMDLINE! variable. Unless not so?

Post Reply