Delayed Expansion and escapes

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Delayed Expansion and escapes

#1 Post by Ed Dyreen » 22 May 2011 20:10

Is there some kind of formula to figure out how many of them you'll need instead of guessing it & trying all possibilities to display a ! ^! ^^^! ^^^^^^^! ^^^^^^^^^^^^! ^^^^^^^^^^^^^^^^^! :|

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

Re: Delayed Expansion and escapes

#2 Post by dbenham » 22 May 2011 20:43

As long as you know how many times the character needs to be escaped it's not difficult. The total number of characters is simply a power of 2.

0 escapes = 2^0 = 1 = !
1 escape = 2^1 = 2 = ^!
2 escapes = 2^2 = 4 = ^^^!
3 escapes = 2^3 = 8 = ^^^^^^^!
etc.

One problem is it is not always obvious how many times you need to escape!

Code: Select all

@echo off
setlocal enableDelayedExpansion
prompt $g
echo on

rem Unquoted uses 2 escapes on each pass, so 2^6=64 chars initially!
set v1=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!
set v2=%v1%
set v3=%v2%
set v

rem Quoted uses only 1 escape per pass, so 2^3=8 chars initially.
set "v1=^^^^^^^!"
set "v2=%v1%"
set "v3=%v2%"
set v


results:

Code: Select all

>rem Unquoted uses 2 escapes on each pass, so 2^6=64 chars initially!

>set v1=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!

>set v2=^^^^^^^!

>set v3=^!

>set v
v1=^^^^^^^^^^^^^^^!
v2=^^^!
v3=!

>rem Quoted uses only 1 escape per pass, so 2^3=8 chars initially.

>set "v1=^^^^^^^!"

>set "v2=^^^!"

>set "v3=^!"

>set v
v1=^^^!
v2=^!
v3=!

Dave Benham

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Delayed Expansion and escapes

#3 Post by Ed Dyreen » 22 May 2011 21:19

Code: Select all

>rem Unquoted uses 2 escapes on each pass, so 2^6=64 chars initially!

>set v1=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!

>set v2=!v1!

>set v3=!v2!

>set v
v1=^^^^^^^^^^^^^^^!
v2=^^^^^^^^^^^^^^^!
v3=^^^^^^^^^^^^^^^!

>rem Quoted uses only 1 escape per pass, so 2^3=8 chars initially.

>set "v1=^^^^^^^!"

>set "v2=!v1!"

>set "v3=!v2!"

>set v
v1=^^^!
v2=^^^!
v3=^^^!
endoftest


Code: Select all

rem Unquoted uses 2 escapes on each pass, so 2^2=4 chars initially!
set v1=^^^!
set v2=!v1!
set v3=!v2!
set v

rem Quoted uses only 1 escape per pass, so 2^1=2 chars initially.
set "v1=^!"
set "v2=!v1!"
set "v3=!v2!"
set v

set "v2=!v1!" and set "v3=!v2!" don't seem to be considered a pass :!:

Code: Select all

>rem Unquoted uses 2 escapes on each pass, so 2^2=4 chars initially!

>set v1=^!

>set v2=!v1!

>set v3=!v2!

>set v
v1=!
v2=!
v3=!

>rem Quoted uses only 1 escape per pass, so 2^1=2 chars initially.

>set "v1=^!"

>set "v2=!v1!"

>set "v3=!v2!"

>set v
v1=!
v2=!
v3=!
endoftest

So that brings me to this conclusion :

Code: Select all

::--------------------------------------------------------------------------------------------------------------------------
@echo off &prompt $g &echo on
setlocal enableDelayedExpansion
rem Escapes are used when a variable is set, echoed, passed to a variable &passed as a parameter.
rem ::(
rem    ::QuickList
rem    ::(
rem       0 escapes    = 2^0 = 1    = !
rem       1 escape    = 2^1 = 2    = ^!
rem       2 escapes    = 2^2 = 4    = ^^^!
rem       3 escapes    = 2^3 = 8    = ^^^^^^^!
rem       4 escapes    = 2^4 = 16    = ^^^^^^^^^^^^^^^!
rem       5 escapes    = 2^5 = 32    = ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!
rem       6 escapes    = 2^6 = 64    = ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!
rem    ::)
rem
rem set is a pass when using set=%variable%
rem Unquoted uses 2 escapes on each pass, so 2^6=64 chars initially!
set v1=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!
set v2=%v1%
set v3=%v2%
set v
rem set is a pass when using set=%variable%
rem Quoted uses only 1 escape per pass, so 2^3=8 chars initially.
set "v1=^^^^^^^!"
set "v2=%v1%"
set "v3=%v2%"
set v
rem set is only one a pass when using set=!variable!
rem Unquoted uses 2 escapes per pass, so 2^2=4 chars initially!
set v1=^^^!
set v2=!v1!
set v3=!v2!
set v
rem set is only one pass when using set=!variable!
rem Quoted uses 1 escapes per pass, so 2^1=2 chars initially.
set "v1=^!"
set "v2=!v1!"
set "v3=!v2!"
set v
@echo off &echo.endoftest &pause &exit
::--------------------------------------------------------------------------------------------------------------------------


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

Re: Delayed Expansion and escapes

#4 Post by jeb » 23 May 2011 02:36

Hi Ed,

there are exactly three different caret phases.

The special character phase:
The caret escapes the next character and is removed, but works only outside of quotes.
Exclamation marks are not important at this phase.

The delayed phase
The caret escapes the next character, only important for exclamation marks, doesn't care about quotes.
AND this phase is only executed if there is at least on exclamation mark in the line.

The call phase:
All carets are doubled, don't care about quotes. This seems to be false, as you normally didn't see double quotes, but this is only, because they are normally removed by the next special character phase.

Samples

Code: Select all

setlocal enableDelayedExpansion
echo without exclam ^^^^ "^^^^"
echo with    exclam ^^^^ "^^^^" !
set "^=one"
set "^^=two"
set "caret=^"
call echo %%!caret!%% caret
call call call call echo ^^^^ "^^^^"


Output

Code: Select all

without exclam ^^ "^^^^"
with    exclam ^ "^^"
two caret
^^ "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"

jeb

Post Reply