Windows 批处理 : findstr not setting ERRORLEVEL within a for loop

标签 windows batch-file cmd windows-10 command-prompt

任何人都可以向我解释为什么以下代码片段会打印出 0:

@echo off
setlocal

for /f %%i in ('cmd /c echo blah') do (
    echo %%i | findstr bin > NUL
    echo %ERRORLEVEL%
)

在 for 循环之外添加另一个等效语句时,它会打印 1 1:

@echo off
setlocal

echo blah | findstr bin > NUL
echo %ERRORLEVEL%

for /f %%i in ('cmd /c echo blah') do (
    echo %%i | findstr bin > NUL
    echo %ERRORLEVEL%
)

我是 Batch 的新手,所以这对我来说有点神秘,因为这两个语句似乎无关。如有任何帮助,我们将不胜感激,谢谢!

最佳答案

问题在于,在代码块(括号内的一系列语句)中,任何%var% 都将被parse 中变量的实际值替换时间

在您的第一个示例中,%errorlevel% 0 并这样回显。在第二个例子中,当遇到 for 时,它是 1,因此它被替换为 1

如果你想显示一个可能在循环中改变的环境变量的值,那么你需要做以下三件事之一:

  1. 调用 setlocal enabledelayedexpansion 并回显 !var! 而不是 %var% - 注意嵌套 的数量您可以激活的 setlocal 指令是有限的。

  2. 调用子程序

  3. 使用语法漏洞。

SO上有很多很多关于delayedexpansion的文章。

粗略地说,您可以简单地使用(注意 - 大小写在批处理中基本上是不相关的,除了循环控制变量的情况(元变量 - %%i in这个实例)

@echo off
setlocal ENABLEDELAYEDEXPANSION

echo blah | findstr bin > NUL
echo %ERRORLEVEL% or !errorlevel!

for /f %%i in ('cmd /c echo blah') do (
    echo %%i | findstr bin > NUL
    echo %ERRORLEVEL% or !errorlevel!
)

另一种方法是动态调用setlocal

@echo off
setlocal

echo blah | findstr bin > NUL
echo %ERRORLEVEL% or !errorlevel!
for /f %%i in ('cmd /c echo blah') do (
    echo %%i | findstr bin > NUL
    setlocal ENABLEDELAYEDEXPANSION
    echo %ERRORLEVEL% or !errorlevel!
    endlocal    
)

这样做的缺点是 endlocal 会取消自上次 setlocal 以来对环境所做的任何更改。另请注意,如果 delayedexpansion 未生效,则 ! 不再是特殊字符。

或者,您可以按传统方式使用 errorlevel:

@echo off
setlocal

echo blah | findstr bin > NUL
echo %ERRORLEVEL% or !errorlevel!

for /f %%i in ('cmd /c echo blah') do (
    echo %%i | findstr bin > NUL
    if errorlevel 1 (echo errorlevel is 1 or greater
    ) else (echo errorlevel is 0
    )
)

请注意,这会查看 errorlevelrun-time 值,if errorlevel n 表示“if errorlevel is n or大于 n"

或者 - 调用一个子程序:

@echo off
setlocal

echo blah | findstr bin > NUL
echo %ERRORLEVEL% or !errorlevel!
for /f %%i in ('cmd /c echo blah') do (
    echo %%i | findstr bin > NUL
    call :show
)
goto :eof

:show
echo %ERRORLEVEL%
goto :eof

注意这里 goto :eof(这里的冒号很重要 - 这意味着“转到物理文件末尾”

或者,使用子程序的特殊版本——语法漏洞利用

@echo off
setlocal

echo blah | findstr bin > NUL
echo %ERRORLEVEL% or !errorlevel!
for /f %%i in ('cmd /c echo blah') do (
    echo %%i | findstr bin > NUL
    call echo %%errorlevel%%
)

关于Windows 批处理 : findstr not setting ERRORLEVEL within a for loop,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36237636/

相关文章:

windows - 我不能在 cmd(或批处理)中使用 msg 命令。我怎样才能解决这个问题?

svn - TortoiseSVN 客户端预提交钩子(Hook)检查正在提交的文件的内容

c# - 通过 Cmd 启动 Windows 应用程序与控制台应用程序

Windows:删除多个子文件夹中的公共(public)文件夹

c++ - Ofstream 在 Windows 临时目录中创建一个文件

windows - 如何快速测试Windows Gadgets?

java - 使用 eclipse 在 Windows 上运行 .sh(来自 linux)脚本

c++ - 我应该如何在 C++ 中正确使用 FormatMessage()?

windows - 从 cmd.exe 或 Windows Run 运行命令的区别

vbscript - vbs cmd 路径空间