Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do SETLOCAL and ENABLEDELAYEDEXPANSION work?

Tags:

batch-file

cmd

I notice in most scripts, the two are usually in the same line as so:

SETLOCAL ENABLEDELAYEDEXPANSION 

Are the two in fact separate commands and can be written on separate lines?

Will setting ENABLEDELAYEDEXPANSION have an adverse effect on a script if it is set on the first lines of the script and not disabled until the end of the script?

like image 399
Anthony Miller Avatar asked Jul 13 '11 13:07

Anthony Miller


People also ask

What does Setlocal Enabledelayedexpansion do?

ENABLEDELAYEDEXPANSION is a parameter passed to the SETLOCAL command (look at setlocal /? ) Its effect lives for the duration of the script, or an ENDLOCAL : When the end of a batch script is reached, an implied ENDLOCAL is executed for any outstanding SETLOCAL commands issued by that batch script.

What is Setlocal Enableextensions Enabledelayedexpansion?

setlocal ENABLEDELAYEDEXPANSION ENABLEEXTENSIONSset variable modifications local to this script, i.e., the change to variable value disappears after the script ends. The variables revert to their original values. Without setlocal, the changes of variables preserves even after the bat script exits.

What is Setlocal and Endlocal in batch?

Issuing a SETLOCAL command, the batch script will inherit all current variables from the master environment/session. Issuing an ENDLOCAL command will restore all environment variables to the state they had before the SETLOCAL was issued.

How do I get rid of the exclamation mark in CMD?

Jaime Ramos sent me this link where the solution can be found: use ^^! . The trick is that a single caret will be used to escape the exclamation mark in the first "pass" of command line interpretation, but delayed variable expansion adds a second "pass" where the exclamation mark will be interpreted.


2 Answers

I think you should understand what delayed expansion is. The existing answers don't explain it (sufficiently) IMHO.

Typing SET /? explains the thing reasonably well:

Delayed environment variable expansion is useful for getting around the limitations of the current expansion which happens when a line of text is read, not when it is executed. The following example demonstrates the problem with immediate variable expansion:

set VAR=before if "%VAR%" == "before" (     set VAR=after     if "%VAR%" == "after" @echo If you see this, it worked ) 

would never display the message, since the %VAR% in BOTH IF statements is substituted when the first IF statement is read, since it logically includes the body of the IF, which is a compound statement. So the IF inside the compound statement is really comparing "before" with "after" which will never be equal. Similarly, the following example will not work as expected:

set LIST= for %i in (*) do set LIST=%LIST% %i echo %LIST% 

in that it will NOT build up a list of files in the current directory, but instead will just set the LIST variable to the last file found. Again, this is because the %LIST% is expanded just once when the FOR statement is read, and at that time the LIST variable is empty. So the actual FOR loop we are executing is:

for %i in (*) do set LIST= %i 

which just keeps setting LIST to the last file found.

Delayed environment variable expansion allows you to use a different character (the exclamation mark) to expand environment variables at execution time. If delayed variable expansion is enabled, the above examples could be written as follows to work as intended:

set VAR=before if "%VAR%" == "before" (     set VAR=after     if "!VAR!" == "after" @echo If you see this, it worked )  set LIST= for %i in (*) do set LIST=!LIST! %i echo %LIST% 

Another example is this batch file:

@echo off setlocal enabledelayedexpansion set b=z1 for %%a in (x1 y1) do (  set b=%%a  echo !b:1=2! ) 

This prints x2 and y2: every 1 gets replaced by a 2.

Without setlocal enabledelayedexpansion, exclamation marks are just that, so it will echo !b:1=2! twice.

Because normal environment variables are expanded when a (block) statement is read, expanding %b:1=2% uses the value b has before the loop: z2 (but y2 when not set).

like image 155
Michel de Ruiter Avatar answered Sep 28 '22 05:09

Michel de Ruiter


ENABLEDELAYEDEXPANSION is a parameter passed to the SETLOCAL command (look at setlocal /?)

Its effect lives for the duration of the script, or an ENDLOCAL:

When the end of a batch script is reached, an implied ENDLOCAL is executed for any outstanding SETLOCAL commands issued by that batch script.

In particular, this means that if you use SETLOCAL ENABLEDELAYEDEXPANSION in a script, any environment variable changes are lost at the end of it unless you take special measures.

like image 40
Alex K. Avatar answered Sep 28 '22 06:09

Alex K.