我有两个 .bat
文件,都使用延迟扩展,以便我可以在 for 循环中设置变量。
下面的示例经过极大简化,只是为了说明问题
脚本one.bat
@echo off
setlocal enableextensions
setlocal enabledelayedexpansion
set j=0
for /L %%i in (1,1,2) do (
set j=%%i
set /A j=!j! + 1
echo %%i !j!
two.bat
echo %%i !j!
)
脚本two.bat
@echo off
setlocal enableextensions
setlocal enabledelayedexpansion
echo Hello World
exit /B 0
从 two.bat
返回时,变量 !j!
丢失,并且 echo
重新打开。
J:\>one
1 2
Hello World
1 !j!
J:\>(
set j=2
set /A j=!j! + 1
echo 2 !j!
two.bat
echo 2 !j!
)
Missing operator.
2 !j!
Hello World
2 !j!
是的,我可以使 two.bat
成为 one.bat
中的子例程,但它有数百行长,我不想维护两个副本同样的逻辑
我在这里缺少什么?
最佳答案
您关于执行从文件 two.bat
返回的假设是错误的,因为只有当您使用 call
command 时才会出现这种情况。 1。
批处理文件 one.bat
在括号内的代码块内运行 two.bat
,该代码块已位于命令堆栈2中,所以该 block 在终止执行之前已经(某种程度上)完成了。
您的输出完美地说明了发生的情况(因此我在这里评论了它):
J:\>one
1 2 /* first loop iteration, the first `echo %%i !j!` in the block is
executed as expected; */
Hello World /* `two.bat` is run; execution does NOT return to `one.bat`,
because there is NO `call`, which would put a return point onto
the stack! the only thing remembered and thus accomplished is
the current command line or parenthesised block; */
1 !j! /* the second `echo %%i !j!` in the block is executed as it is
still buffered, but `two.bat` is already quit, hence implicit
`endlocal` commands have been executed, so all the nested
`setlocal` commands in your scripts are cancelled and delayed
expansion is disabled (default state); moreover, variable `j` is
no longer defined here; */
/* at this point, the parenthesised block, which is the loop body,
has been executed, hence batch file context is left and Command
Prompt context applies, so `@echo off` from `one.bat` does no
longer apply here; */
J:\>( // this block is nothing but the echo of the second loop iteration,
set j=2 // which is still buffered;
set /A j=!j! + 1
echo 2 !j!
two.bat
echo 2 !j!
)
Missing operator. /* this error message is caused by the attempt to execute
`set /A j=!j! + 1` (remember that delayed expansion is no longer
enabled and `j` is undefined); */
2 !j! // first `echo %%i !j!` in the buffered second loop iteration;
Hello World /* `two.bat` is run again; afterwards, batch file context is left
again and Command Prompt context applies; */
2 !j! // second `echo %%i !j!` in the buffered second loop iteration;
要证明执行是否发生在批处理文件或命令提示符上下文中,只需将 set/A j
放在 one.bat
的循环体中作为最后一个命令,这样在输出 1 !j!
和第二个 2 !j!
之后,您将获得额外的输出 0
,因为 set/A
在批处理文件上下文中不返回任何内容,但它在命令提示符上下文中输出(最后)结果(没有尾随换行符); 0
的值表明 j
不再设置。
1) 有一些异常(exception):被调用的批处理文件涉及管道,或者由 for /F
loop 运行和解析。 ,因为批处理文件在新的 cmd.exe
中运行此类情况的实例。
2) 如果被调用的批处理文件包含在具有串联命令的行中,情况也是如此,因此诸如 two.bat & echo Fine
之类的内容将回显 Fine
执行 two.bat
.
关于windows - 如何从另一个 Windows 批处理脚本调用一个 Windows 批处理脚本,并在两者中都启用延迟扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64022201/