.bat 文件中的奇怪范围问题 [英] Weird scope issue in .bat file

查看:22
本文介绍了.bat 文件中的奇怪范围问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个简单的 .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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆