【问题标题】:Batch /a doesn't store a value批处理 /a 不存储值
【发布时间】:2014-10-11 04:42:23
【问题描述】:

代码:

@echo off
set /a x=5
set /a TNUM=%x%-3
echo %TNUM%
pause

输出是:

ECHO is off

那么,我该如何解决这个问题?

这是完整的代码:

@echo off
setlocal enableextensions
set /a COLUMNS=60
set /a ROWS=40
mode con: cols=%COLUMNS% lines=%ROWS%

:main
    set /a xpos=5
    set /a ypos=5

    call:displayScreen

    pause >nul
    goto :eof

::FUNCTIONS::
:displayScreen
    set /a TEMPR=%ROWS%-3
    for /l %%c in (1,1,%COLUMNS%) do echo|set /p=#
    for /l %%r in (1,1,%TEMPR%) do (
        echo|set /p=#
        if %%r==%ypos% (
            set /a TNUM=%xpos%-3
            echo %TNUM%
            for /l %%t in (1,1,%TNUM%) do echo|set /p=A
            echo|set /p=o
            set /a TNUM=%COLUMNS%-%xpos%-1
            for /l %%t in (1,1,%TNUM%) do echo|set /p=A
        ) else (
            set /a TNUM=%COLUMNS%-2
            for /l %%t in (1,1,%TNUM%) do (
                echo|set /p=A
            )
        )
        echo|set /p=#
        echo.
    )
    for /l %%c in (1,1,%COLUMNS%) do echo|set /p=#

主要问题出在显示屏功能上。它应该打印屏幕并在我给它的两个坐标处设置 x。我输入了 echo %TNUM% 这样我就可以看到里面有什么,它总是等于“”。

【问题讨论】:

  • 你试过添加setlocal ENABLEDELAYEDEXPANSION吗?然后将%x%替换为!x!?
  • 我只是在学习batch,所以不太了解。我将如何适应代码?你介意编辑一下吗?
  • 对我来说非常愉快。你是用剪切粘贴的方式发帖吗?
  • +1 您的代码运行良好。始终展示您实际在做什么,因为如果您不这样做,那么您将得到可能在实际任务中不起作用的答案。
  • @foxidrive 我添加了完整的代码。

标签: variables batch-file scripting


【解决方案1】:

主要有三种方式来获得指示的行为

1 - 变量扩展问题。在批处理文件中,行或行块(括号中的一组行)被解析、执行,然后在下一行/块上重复操作。

在解析阶段,所有对变量(任何%var%)的读取操作都会从代码中删除,并用存储在变量之前开始执行代码行/代码块的值替换它们。

因此,如果在行/块内更改了变量的值,则在执行阶段无法在同一行/块内读取/检索该值。为什么?因为在行/块中没有读取操作来检索变量的值。这段代码

set x=0
if 1==1 (
    set x=1
    set y=%x%
)
echo x=%x% y=%y%

会回显到控制台x=1 y=0 为什么?当解析if 代码块(完整块)时,读取操作(=%x%)在解析时替换为解析时变量内的值,并且执行的代码是

if 1==1 (
    set x=1
    set y=0  <- Read operation in x replaced with its value at parse time
)

即存储在x中的改变值无法取回。

这种情况通常使用延迟扩展来解决。这是一种可以通过命令setlocal enabledelayedexpansion 激活的行为,并且允许程序员在需要的地方更改访问变量内容的语法,从%var%!var!,向解析器指示变量的扩展(用变量的值替换读操作)必须延迟到执行阶段。在建议的样本中应该是

setlocal enabledelayedexpansion   <- delayed expansion enabled
set x=0
if 1==1 (
    set x=1
    set y=!x!  <- Read operation delayed
)
echo x=%x% y=%y%

2 - 空格。变量声明的一个习惯性问题是

set /a TNUM = %x%-3
           ^.......This value is included in the variable name

空格包含在变量名中,回显%TNUM% 失败,因为这不是变量名,而是命名为%TNUM %

但是我忘记了,@jeb 在 cmets 中更正,而 setset /p 表现出这种行为,使用 set /a 时不会发生这种情况。在这种情况下,将使用具有不同规则的解析器(例如,它允许变量引用而无需预先扩展)并且指示的空间将被抑制。

3 - 您的机器默认禁用扩展。如果扩展被禁用,set /a 将不起作用并且不会为变量分配任何值

@echo off
    setlocal enableextensions
    set /a x=5
    set /a TNUM=x-3
    echo %TNUM%

总结,要执行echo %TNUM%这一行并获得指示的ECHO is off,需要在解析该行时TNUM未定义或仅包含空格或制表符。

作为先验,当执行set /a TNUM=%x%-3 行时,会为变量分配一个值(至少是-3),看来您的问题是情况1(回显值在执行之前被替换) 或第 3 种情况(由于 set 操作失败,您无法回显)。

已编辑 发布所有代码后,问题在于扩展延迟。

@echo off
    setlocal enableextensions enabledelayedexpansion
    set /a COLUMNS=60
    set /a ROWS=40
    mode con: cols=%COLUMNS% lines=%ROWS%

:main
    set /a xpos=5
    set /a ypos=5

    call :displayScreen

    pause >nul
    goto :eof

::FUNCTIONS::
:displayScreen
    set /a TEMPR=%ROWS%-3
    for /l %%c in (1,1,%COLUMNS%) do echo|set /p=#
    for /l %%r in (1,1,%TEMPR%) do (
        echo|set /p=#
        if %%r==%ypos% (
            set /a TNUM=%xpos%-3
            for /l %%t in (1,1,!TNUM!) do echo|set /p=A
            echo|set /p=o
            set /a TNUM=%COLUMNS%-%xpos%
            for /l %%t in (1,1,!TNUM!) do echo|set /p=A
        ) else (
            set /a TNUM=%COLUMNS%-2
            for /l %%t in (1,1,!TNUM!) do (
                echo|set /p=A
            )
        )
        echo|set /p=#
    )
    for /l %%c in (1,1,%COLUMNS%) do echo|set /p=#

【讨论】:

  • 使用/a选项时不存在空间问题,只有不带选项或使用/p
  • 我添加了完整的代码并做了 setlocal enableextentions。我可能做错了什么可怕的事情。感谢您的所有帮助!
  • @Twonty2,您的问题是扩展延迟。见点数 1
  • 我知道你是对的 MC ND 但读你的第一段让我头疼。 ;) 我发现很难听懂这些话。
  • @Twonty2,如果您尝试检索的值已在您尝试读取的同一块内发生更改,您只需需要延迟扩展。 xpos 是在块外定义的(for /l %%r),它的值在块内不会改变,所以不需要使用延迟扩展。但是TNUM 被更改在块内 并且需要在同一块内检索更改的值,因此需要延迟扩展。无论如何,您可以使用!xpos!,它也可以使用。我只是想展示 “需要的地方” 是如何工作的。
【解决方案2】:

它似乎没有等待评估 %x%。因此,您可以添加 ENABLEDELAYEDEXPANSION 以便它等待评估 x 以便在数学运算期间对其进行初始化。

@echo off
setlocal ENABLEDELAYEDEXPANSION
set /a x=5
set /a TNUM=!x!-3
echo !TNUM!
endlocal
pause

【讨论】:

  • 哦,好吧。这就说得通了。一会儿我试试,谢谢!
  • 这在上面的完整代码中是正确的,尽管 !x! 可以只是 set /a 命令中的普通变量名称 x - 你实现了这个答案吗?除非您真的需要核对变量,否则您也可以将 endlocal 排除在外。
【解决方案3】:

在块语句(a parenthesised series of statements) 中,整个块被解析并然后执行。块中的任何%var% 都将替换为该变量的值在解析块时 - 在块执行之前。

由于for...%%r... 循环执行一个代码块(从do 之后的( 到匹配的)),那么出现在该块中的任何%tnum% 都将被@ 的值替换987654328@ 解析循环时Tnum 在块启动时没有任何值,所以显示的就是这个。

tnum 是在循环中设置的,因此由于您在程序开始时的 setlocal enabledelayedexpansion 语句中将 enabledelayedexpansion 设置为 ON,因此您需要使用 !tnum!代替循环中的 %tnum% 以在 tnum 更改时访问它的值。

【讨论】:

    猜你喜欢
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    • 2019-07-23
    • 2012-10-10
    • 2015-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多