Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Batch file nested setlocal - setting optional arguments only once

I have a batch file with some functions. Each function uses setlocal so that its variables do not contaminate the main batch script. I've noticed that I only need the argument ENABLEDELAYEDEXPANSION the first time in the main batch script rather than in each nested setlocal. For example:

@echo off
setlocal ENABLEDELAYEDEXPANSION

set VAR=hi
CALL :function

echo bye
exit /b 0

:function
setlocal
echo !VAR!
exit /b 0

Is this allowed in batch file because I can't find it documented except as noted below. It's certainly a lot easier than to write just setlocal for each function rather than specify the additional arguments.

setlocal /? says this regarding ENABLEDELAYEDEXPANSION:

These modifications last until the matching ENDLOCAL command, regardless of their setting prior to the SETLOCAL command.

So maybe that would mean even with another setlocal the settings stay the same?

like image 666
loop Avatar asked Feb 11 '23 07:02

loop


1 Answers

Well, you could answer your own question by writing some simple tests. But I'll tell you that the answer is yes, you only need to enable delayed expansion once. Every SETLOCAL afterward will inherit the prior delayed expansion state, unless explicitly over-ridden by DisableDelayedExpansion.

@echo off
echo delayed Expansion normally starts out disabled: !temp!
setlocal enableDelayedExpansion
echo delayed exapnsion now enabled: !temp!
call :test
exit /b

:test
setlocal
echo delayed expansion still enabled: !temp!
exit /b

If you are learning batch, then you should expect to be doing lots of experiments because the documentation is quite poor, and sometimes simply wrong.


Your strategy of only enabling delayed expansion once is good only if you know that it is OK for it to be enabled throughout the entire script.

It is true that delayed expansion solves a lot of nasty problems in batch, but unfortunately it can also cause problems.

Expansion of CALL arguments %1 or FOR variables %%A are corrupted if the value contains ! and delayed expansion is enabled. So many moderately complex scripts that I write require careful management of the delayed expansion state.

Within a single routine, you are in a position to know the state at any given time. But at the start of a subroutine or function, you may not know the state of the caller. As a general rule, I explicitly enable or disable delayed expansion at the top of each routine if my routine requires a particular state.


A word of caution - Each new instantiation of cmd.exe does NOT inherit the delayed expansion state from the prior session. Normally every cmd.exe session starts off with delayed expansion disabled.

This is important because both pipes and FOR /F %%A IN ('someCommand') DO ... implicitly launch new cmd.exe sessions. See Why does delayed expansion fail when inside a piped block of code? for more info.

like image 68
dbenham Avatar answered Apr 27 '23 17:04

dbenham