Bur*_*ley 5 variables cmd batch-file
当CMD.exe终止时,为什么下面的批处理文件不保留变量
@echo off
cmd /c "set var=hi"
if defined var (echo var is defined ("var=%var%")) else (echo var isn't defined)
pause
exit
Run Code Online (Sandbox Code Playgroud)
有没有办法使用CMD/c,同时保留变量?为什么CMD/c不保留变量?
CMD /C 启动一个新的子进程,该子进程有自己的环境空间,变量存储在内存中。当该进程终止时,关联的环境空间就会丢失,因此您当然会丢失在那里定义的任何变量的定义。
子进程不可能直接访问或操作父进程的变量。
如果您正在执行一个简单的命令并可以控制任何输出,那么您可以将定义写入 stdout 并让 FOR /F 捕获输出,以便您可以在父进程中设置值。但你需要延迟扩展。
注意 - 这个例子相当愚蠢,但它应该能说明问题
for /f "delims=" %%A in ('cmd /v:on /c "set var=hi&echo "var=!var!""') do set %%A
Run Code Online (Sandbox Code Playgroud)
但就确定引用的内容、需要转义的内容而言,事情可能会变得复杂……
如果您创建一个执行该工作的批处理脚本并使用 FOR /F 执行它,那么生活可以得到简化。
测试.bat
@echo off
set var1=hi
set var2=Ain't this fun
set var3=bye
setlocal enableDelayedExpansion
for %%V in (var1 var2 var3) do echo "%%V=!%%V!"
Run Code Online (Sandbox Code Playgroud)
主程序
@echo off
for /f "delims=" %%A in ('cmd /c test.bat') do set %%A
Run Code Online (Sandbox Code Playgroud)
实际上,FOR /F 使用隐式 CMD /C,并且您不再需要在命令中启用延迟扩展,因此您可以放弃显式 CMD /C
@echo off
for /f "delims=" %%A in ('test.bat') do set %%A
Run Code Online (Sandbox Code Playgroud)
如果您无法控制输出,则必须将值写入临时文件,然后主脚本可以加载该临时文件。您可能想编写一个定义变量的临时批处理脚本,但随后您将面临必须转义某些字符的风险,具体取决于变量的内容。最安全的选择是使用延迟扩展写出变量名称和值,并让父进程使用 FOR /F 加载它们。
测试2.bat
@echo off
set var1=hi
set var2=Ain't this fun
set var3=bye
echo Here is some output that must be preserved, unrelated to variables
setlocal enableDelayedExpansion
(for %%V in (var1 var2 var3) do echo "%%V=!%%V!") >"%temp%\vars.temp"
Run Code Online (Sandbox Code Playgroud)
主程序
@echo off
setlocal disableDelayedExpansion
cmd /c test2.bat
call "%temp%\vars.bat"
for /f "usebackq delims=" %%V in ("%temp%\vars.temp") do set "%%V"
del "%temp%\vars.temp"
Run Code Online (Sandbox Code Playgroud)
请注意,加载变量时必须在主进程中禁用延迟扩展,否则扩展!时将丢失值中的任何字符。%%V
但为了保持鲁棒性,您应该采取措施确保每个实例化都使用唯一的临时文件名,以便同时运行不会互相干扰。