¿Cómo funcionan SETLOCAL y ENABLEDELAYEDEXPANSION?

Noté que en la mayoría de los guiones, los dos generalmente están en la misma línea:

SETLOCAL ENABLEDELAYEDEXPANSION 

¿Son los dos, de hecho, comandos separados y se pueden escribir en líneas separadas?

¿La configuración de ENABLEDELAYEDEXPANSION tendrá un efecto adverso en un script si está configurado en las primeras líneas del script y no se desactiva hasta el final del script?

ENABLEDELAYEDEXPANSION es un parámetro pasado al comando SETLOCAL (mira setlocal /? )

Su efecto vive durante la duración del guión, o un ENDLOCAL :

Cuando se llega al final de un script por lotes, se ejecuta un ENDLOCAL implícito para cualquier SETLOCAL pendiente de SETLOCAL emitido por ese script por lotes.

En particular, esto significa que si usa SETLOCAL ENABLEDELAYEDEXPANSION en una secuencia de comandos, cualquier cambio de variable de entorno se perderá al final a menos que tome medidas especiales .

Creo que deberías entender qué es la expansión retrasada. Las respuestas existentes no lo explican (suficientemente) en mi humilde opinión.

Escribir SET /? lo explica razonablemente bien:

La expansión de variables de entorno retrasadas es útil para evitar las limitaciones de la expansión actual que ocurre cuando se lee una línea de texto, no cuando se ejecuta. El siguiente ejemplo demuestra el problema con la expansión de variables inmediata:

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

nunca mostraría el mensaje, ya que el% VAR% en ambas declaraciones IF se sustituye cuando se lee la primera instrucción IF, ya que lógicamente incluye el cuerpo del IF, que es una statement compuesta. Entonces, la IF dentro de la statement compuesta realmente compara “antes” con “después”, lo que nunca será igual. Del mismo modo, el siguiente ejemplo no funcionará como se esperaba:

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

ya que NO creará una lista de archivos en el directorio actual, sino que simplemente establecerá la variable LIST en el último archivo encontrado. Nuevamente, esto se debe a que% LIST% se expande solo una vez cuando se lee la instrucción FOR, y en ese momento la variable LIST está vacía. Entonces, el bucle FOR real que estamos ejecutando es:

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

que simplemente sigue configurando LIST al último archivo encontrado.

La expansión variable de entorno retrasada le permite usar un carácter diferente (el signo de exclamación) para expandir las variables de entorno en el momento de la ejecución. Si la expansión de la variable retrasada está habilitada, los ejemplos anteriores se pueden escribir de la siguiente manera para que funcionen como se esperaba:

 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% 

Otro ejemplo es este archivo por lotes:

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

Esto imprime x2 e y2 : cada 1 es reemplazado por un 2.

Sin setlocal enabledelayedexpansion , las exclamaciones son solo eso, por lo que se repetirá !b:1=2! dos veces.

Debido a que las variables de entorno normales se expanden cuando se lee una instrucción (bloque), al expandir %b:1=2% usa el valor b anterior al ciclo: z2 (pero y2 cuando no está establecido).

La parte ENABLEDELAYEDEXPANSION se REQUIERE en ciertos progtwigs que usan expansión retrasada, es decir, que toma el valor de las variables que se modificaron dentro de los comandos IF o FOR al encerrar sus nombres en signos de exclamación.

Si habilita esta expansión en una secuencia de comandos que no lo requiere, la secuencia de comandos se comporta diferente solo si contiene nombres encerrados en signos de exclamación. !¡ESTAS!. Por lo general, el nombre solo se borra, pero si existe una variable con el mismo nombre por casualidad, el resultado es impredecible y depende del valor de dicha variable y del lugar donde aparece.

La parte SETLOCAL se REQUIERE en solo unos pocos progtwigs especializados (recursivos), pero se usa comúnmente cuando quiere asegurarse de no modificar ninguna variable existente con el mismo nombre por casualidad o si desea eliminar automáticamente todas las variables utilizadas en su progtwig. Sin embargo, debido a que no hay un comando separado para habilitar la expansión retrasada, los progtwigs que lo requieren también deben incluir la parte SETLOCAL.

Con frecuencia, existe un problema real porque las variables establecidas en el interior no se exportarán cuando termine ese archivo por lotes. Entonces no es posible exportar, lo que nos causó problemas. Como resultado, simplemente configuré el registro SIEMPRE que usé la expansión retrasada (no sé por qué no es el predeterminado, podría tratarse de problemas de compatibilidad de velocidad o herencia).