0

I have an "environment file" script where I set multiple variable used in my automation routines. One variable is a password and it has a ! symbol. My issue is that in my main script where I need to use that variable uses SETLOCAL ENABLEDELAYEDEXPANSION therefore the variable isn't rendering correctly.

How do I solve for this?

_env.cmd

SET "FTP_PSSWRD=CatDog!"

MainScript.cmd

SETLOCAL ENABLEDELAYEDEXPANSION
CALL "_env.cmd"

ECHO "%FTP_PSSWRD%"
Compo
  • 36,585
  • 5
  • 27
  • 39
chrtak
  • 43
  • 6
  • You have not demonstrated to us a reason why the delayed expansion in necessary. Please submit the actual script content, _instead of pointlessly omitting it_, and let us decide, or at least offer an efficient workaround for your particular user case. – Compo Jul 09 '23 at 23:17
  • Do not use [delayed variable expansion](https://ss64.com/nt/delayedexpansion.html). It is always possible to write batch file code in a manner to either avoid the requirement using delayed variable expansion at all or use it without interpreting exclamation marks in file/folder names or in values of environment variables as beginning/end of a delayed expanded variable reference. In the posted code should be used `setlocal EnableExtensions DisableDelayedExpansion` together with `@echo off` at the beginning of `MainScript.cmd` for a complete definition of the required execution environment. – Mofi Jul 10 '23 at 04:57
  • Please read [this answer](https://stackoverflow.com/a/67039507/3074564) for details about the commands __SETLOCAL__ and __ENDLOCAL__. It is about a task where once batch file passes environment variable names to another batch file which does something using delayed variable expansion and returns string values to the main batch files assigned to the environment variables of which names are passed to the child batch file. The code is fully explained. – Mofi Jul 10 '23 at 04:59
  • BTW: It would be better to use `CALL "%~dp0_env.cmd"` instead of just `CALL "_env.cmd"` if the batch file `_env.cmd` is always in the directory of `MainScript.cmd`. Then the call of the child batch file works even with current directory of `cmd.exe` process is not the directory containing both batch files. `%~dp0` expands to full directory path of the currently processed batch file always ending with a backslash which is the directory separator on Windows. – Mofi Jul 10 '23 at 05:03

1 Answers1

1

There exists different solutions.

  1. Modify the exclamation marks in the password

    SET "FTP_PSSWRD=CatDog^!"

But be aware, when there are carets, they need to be escaped, too.

SET "FTP_PSSWRD=CatDog^! and a single ^^ caret"

But if there are only carets and no exclamation marks

SET "FTP_PSSWRD=A single ^ caret"

But now, it only works, if delayed expansion is enabled

  1. Using DisableDelayedExpansion and return from scope Call your env.cmd file, but use before:

    setlocal DisableDelayedExpansion

After the call, you need to leave the setlocal scope and transfer the variable.
See Make an environment variable survive ENDLOCAL

setlocal DisableDelayedExpansion
CALL "_env.cmd"
%endlocal% FTP_PSSWRD

ECHO "!FTP_PSSWRD!"
  1. Using a macro that creates %%! and %%^ for-meta-variables, they expands to ! and ^ independent of the delayed expansion mode

FOR /F "tokens=1 delims== " %%! in ("!=! ^^^!") DO ^
FOR /F %%^^ in ("^ ^^^^%%!=%%!") DO ^
set ^"$lib.macrodefine.free=@FOR /F "tokens=1 delims== " %%%%! in ("%%!=%%! %%^%%^%%^%%!") DO ^
@FOR /F %%%%^^%%^^ in ("%%^ %%^%%^%%^%%^%%^%%!=%%^%%!") DO @"


setlocal EnableDelayedExpansion
call :test
endlocal

setlocal DisableDelayedExpansion
call :test
endlocal
exit /b

:test
%$lib.macrodefine.free% SET "FTP_PSSWRD=CatDog%%!"
set "FTP_PSSWRD"
jeb
  • 78,592
  • 17
  • 171
  • 225