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

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

问题描述

我在写一个简单的.bat文件,我已经碰到一些怪异的行为。有几个地方,我必须做一个简单的if / else,但是块内code似乎没有正常工作。

下面是一个演示该错误的简单情况:

 关闭@echo集MODE = FOOBAR如果%〜1==(
  集MODE = ALL
  回波模式:%MODE%
)其他(
  集MODE =%〜1
  回波模式:%MODE%

回波模式:%MODE%

我得到的输出是:

  C:\\>测试下的test.bat
模式:FOOBAR
模式:测试

为什么code块内部回声没有得到变量的新价值?在实际的code我写我需要​​建立一些变量的的if / else范围内引用它们。我可以关掉这个使用标签和GOTO,而不是一个的if / else,但是这似乎并不几乎一样干净。

是什么原因造成这种现象?是否有code块?

中的变量某种限制
解决方案

您正在运行到CMD的静态变量扩展的问题。 MODE变量只计算一次。你可以看到这一点,如果你省略了@echo下线。

从集/?文档:


  

最后,对于延迟的环境变量扩展支持有
  被添加。这种支持始终是
  默认被禁用,但也可以是
  通过启用/ V命令/禁用
  行开关CMD.EXE。请参阅CMD /?


  
  

延迟环境变量扩充是让周围有用
  的电流的限制
  扩展它发生在一个线
  文本阅读,而不是在执行的时候。
  下面的例子演示了
  直接变量问题
  扩展:

 组VAR =前
 如果%VAR%==之前(
     组VAR =后
     如果%VAR%== @echo后,如果你看到这一点,它的工作
 )


  
  

绝不会显示消息,因为
  在这两个IF语句中的%VAR%是
  当第一IF取代的
  声明被读取,因为它在逻辑
  包括中频,这是身体
  复合语句。因此,IF
  里面的复合语句是
  真的比较之前和之后
  它永远不会相等。同样的,
  下面的例子将无法正常工作
  预计:

 集列表=
用于%I IN(*)并设置LIST =%LIST%%我
回声%LIST%


  
  

,它不会建了一个列表
  在当前的目录中的文件,但
  而不是只会设置列表
  变量的最后一个文件中。
  再次,这是因为%LIST%是
  扩大只是一次当FOR
  语句被读出,并在该时间
  List变量是空的。所以
  实际的,因为我们正在执行循环是:

 为%i的(*)并设置LIST =%I


  
  这个循环继续将LIST到


  最后的文件中找到。


  
  

延迟环境变量扩充
  允许您使用不同的
  字符(惊叹号),以
  扩大环境变量在
  执行时间处理时间。如果延迟变量
  扩充被启用,上述
  实施例可以写成如下
  按预期工作:

 组VAR =前
如果%VAR%==之前(
    组VAR =后
    如果!VAR! == @echo后,如果你看到这一点,它的工作
)集列表=
用于%I IN(*)并设置LIST =!LIST! %一世
回声%LIST%


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%

The output I'm getting is:

C:\>test.bat test
mode: FOOBAR
mode: test

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?

解决方案

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.

From the set /? documentation:

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
 )

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%

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

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天全站免登陆