Windows Batch:findstr未在for循环中设置错误级别

Jam*_* Ko 1 windows cmd batch-file command-prompt windows-10

谁能向我解释以下摘要的打印原因0:

@echo off
setlocal

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

在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%
)
Run Code Online (Sandbox Code Playgroud)

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

Mag*_*goo 5

问题在于,在code block(带括号的一系列语句中)任何%var%变量都将被变量的实际值代替parse time。

欣你的第一个例子,%errorlevel% 0并如此回应。在第二个示例中,是1在for遇到时,因此将其替换为1。

如果要显示可能在循环中更改的环境变量的值,则需要执行以下三种操作之一:

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

  2. 调用子程序

  3. 使用语法漏洞。

delayedexpansion关于SO的文章很多。

粗略地讲,您可以简单地使用(注意-大小写在批处理中基本上无关紧要,除了循环控制变量的情况(在这种情况下metavariable-%%i

@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!
)
Run Code Online (Sandbox Code Playgroud)

另一种方法是动态调用 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    
)
Run Code Online (Sandbox Code Playgroud)

这样做的缺点是,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
    )
)
Run Code Online (Sandbox Code Playgroud)

请注意,这将查看的run-time值,errorlevel并if errorlevel n表示“如果错误级别为n 或大于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
Run Code Online (Sandbox Code Playgroud)

请注意,此处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%%
)
Run Code Online (Sandbox Code Playgroud)