.bat 文件中的奇怪范围问题 [英] Weird scope issue in .bat file
问题描述
我正在编写一个简单的 .bat 文件,但遇到了一些奇怪的行为.有几个地方我必须做一个简单的 if/else,但块内的代码似乎不能正常工作.
I'm writing a simple .bat file and I've run into some weird behavior. There are a couple places where I have to do a simple if/else, but the code inside the blocks don't seem to be working correctly.
这是一个演示错误的简单案例:
Here's a simple case that demonstrates the error:
@echo off
set MODE=FOOBAR
if "%~1"=="" (
set MODE=all
echo mode: %MODE%
) else (
set MODE=%~1
echo mode: %MODE%
)
echo mode: %MODE%
我得到的输出是:
C:>test.bat test
mode: FOOBAR
mode: test
为什么代码块里面的echo没有得到变量的新值?在我编写的实际代码中,我需要构建一些变量并在 if/else 的范围内引用它们.我可以将其切换为使用标签和 goto 而不是 if/else,但这似乎不太干净.
Why is the echo inside the code block not getting the new value of the variable? In the actual code I'm writing I need to build a few variables and reference them within the scope of the if/else. I could switch this to use labels and gotos instead of an if/else, but that doesn't seem nearly as clean.
是什么导致了这种行为?代码块内的变量是否有某种限制?
What causes this behavior? Is there some kind of limit on variables within code blocks?
推荐答案
您遇到了 cmd 的静态变量扩展问题.MODE 变量只计算一次.如果您在离线时省略@echo,您可以看到这一点.
You are running into the problem of cmd's static variable expansion. The MODE variable is only evaluated once. You can see this if you omit the @echo off line.
从集/?文档:
终于支持延迟环境变量扩展了已添加.这种支持总是默认情况下禁用,但可能会通过/V 命令启用/禁用行切换到 CMD.EXE.看 CMD/?
Finally, support for delayed environment variable expansion has been added. This support is always disabled by default, but may be enabled/disabled via the /V command line switch to CMD.EXE. See CMD /?
延迟环境变量扩展对绕过很有用当前的限制当一行文本被读取,而不是在它被执行时.下面的例子演示了直接变量问题扩展:
Delayed environment variable expansion is useful for getting around the limitations of the current expansion which happens when a line of text is read, not when it is executed. The following example demonstrates the problem with immediate variable expansion:
set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "%VAR%" == "after" @echo If you see this, it worked
)
永远不会显示消息,因为两个 IF 语句中的 %VAR% 是当第一个 IF 时替换语句被读取,因为它在逻辑上包括 IF 的主体,即一个复合语句.所以如果复合语句里面是真正比较之前"和之后"这永远不会相等.相似地,以下示例将无法正常工作预期:
would never display the message, since the %VAR% in BOTH IF statements is substituted when the first IF statement is read, since it logically includes the body of the IF, which is a compound statement. So the IF inside the compound statement is really comparing "before" with "after" which will never be equal. Similarly, the following example will not work as expected:
set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%
因为它不会建立一个列表当前目录下的文件,但是相反只会设置 LIST变量到最后找到的文件.同样,这是因为 %LIST% 是当 FOR 时只扩展一次声明被读取,并且在那个时候LIST 变量为空.所以我们正在执行的实际 FOR 循环是:
in that it will NOT build up a list of files in the current directory, but instead will just set the LIST variable to the last file found. Again, this is because the %LIST% is expanded just once when the FOR statement is read, and at that time the LIST variable is empty. So the actual FOR loop we are executing is:
for %i in (*) do set LIST= %i
它只是不断地将 LIST 设置为找到的最后一个文件.
which just keeps setting LIST to the last file found.
延迟环境变量扩展允许您使用不同的字符(感叹号)到扩展环境变量在执行时间处理时间.如果延迟变量启用扩展,以上例子可以写成如下按预期工作:
Delayed environment variable expansion allows you to use a different character (the exclamation mark) to expand environment variables at execution time. If delayed variable expansion is enabled, the above examples could be written as follows to work as intended:
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%
这篇关于.bat 文件中的奇怪范围问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!