Windows批处理:findstr未在for循环中设置ERRORLEVEL
有人能解释一下为什么下面的代码片段会打印Windows批处理:findstr未在for循环中设置ERRORLEVEL,windows,batch-file,cmd,windows-10,command-prompt,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: @echo off setlocal echo blah | findstr bin > NUL echo %ERRORLEVEL% for /f %
0
:
@echo off
setlocal
for /f %%i in ('cmd /c echo blah') do (
echo %%i | findstr bin > NUL
echo %ERRORLEVEL%
)
在for循环之外添加另一条等效语句时,它将打印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%
)
我对批处理有点生疏,所以这对我来说有点神秘,因为这两个语句似乎不相关。在此方面的任何帮助都将不胜感激,谢谢 更新:
如果您将您的echo%ERRORLEVEL%
语句放在for语句的结束)
之后,它将按预期工作
for /f %%i in ('cmd /c echo blah') do (
echo %%i | findstr bin > NUL
)
echo %ERRORLEVEL%
我在这里有点猜测,因为确切的“确定”原因,但肯定是setlocal
引起的。我假设for循环中ERRORLEVEL的值是cmd/c…
语句的结果。这似乎是一种奇怪的行为,但我在批处理文件中见过更糟糕的行为
如果在开始时删除setlocal
,它将正常工作
原件:
findstr
在运行时设置errorlevel
。因此,echo%errorlevel%
将始终输出0
例如,下面的findstr语句是成功的,因此它输出匹配的行(传递给它的唯一行):
此语句未成功(findstr不输出任何内容)且errorlevel设置为1时:
C:\>echo blah_in | findstr bin
C:\>echo %errorlevel%
1 ; failed
更新:
如果您将您的echo%ERRORLEVEL%
语句放在for语句的结束)
之后,它将按预期工作
for /f %%i in ('cmd /c echo blah') do (
echo %%i | findstr bin > NUL
)
echo %ERRORLEVEL%
我在这里有点猜测,因为确切的“确定”原因,但肯定是setlocal
引起的。我假设for循环中ERRORLEVEL的值是cmd/c…
语句的结果。这似乎是一种奇怪的行为,但我在批处理文件中见过更糟糕的行为
如果在开始时删除setlocal
,它将正常工作
原件:
findstr
在运行时设置errorlevel
。因此,echo%errorlevel%
将始终输出0
例如,下面的findstr语句是成功的,因此它输出匹配的行(传递给它的唯一行):
此语句未成功(findstr不输出任何内容)且errorlevel设置为1时:
C:\>echo blah_in | findstr bin
C:\>echo %errorlevel%
1 ; failed
这应该行得通
cmd中的for循环从技术上讲是一行,因此变量只展开一次。使用感叹号而不是百分比和“ENABLEDELAYEDEXPANSION”应该可以解决这个问题
这应该行得通
cmd中的for循环从技术上讲是一行,因此变量只展开一次。使用感叹号而不是百分数和“ENABLEDELAYEDEXPANSION”应该可以解决这个问题。问题是在
代码块
(括号内的一系列语句)中,任何%var%
都将替换为解析时变量的实际值
在您的第一个示例中,%errorlevel%
0
,并以这样的方式进行回音。在第二个示例中,遇到
的时,它是1
,因此它被1
替换
如果要显示可能在循环中更改的环境变量的值,则需要执行以下三项操作之一:
调用setlocal enabledelayedexpansion
并回显!瓦尔代码>而不是%var%
-请注意,可以激活的嵌套setlocal
指令数量有限
调用子程序
利用语法漏洞
有很多很多关于延迟扩展的文章
粗略地说,您可以简单地使用(注意-除了循环控制变量(metavariable
-%%i
在本例中),case在批处理中基本上是无关的)
另一种方法是动态调用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
)
)
请注意,这将查看errorlevel
的运行时值,如果errorlevel n
表示“如果errorlevel为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
注意这里的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%%
)
问题是在代码块
(括号内的一系列语句)中,任何%var%
都将在解析时被变量的实际值替换
在第一个示例中,%errorlevel%
0
并以这样的方式进行回音。在第二个示例中,当遇到for
时,它是1
,因此它被1
替换
如果要显示可能在循环中更改的环境变量的值,则需要执行以下三项操作之一:
调用setlocal enabledelayedexpansion
和echo!var!
,而不是%var%
——注意,可以激活的嵌套setlocal
指令的数量是有限的
调用子程序
利用语法漏洞
有很多很多关于延迟扩展的文章
粗略地说,您可以简单地使用(注意-除了循环控制变量(metavariable
-%%i
在本例中),case在批处理中基本上是无关的)
另一种方法是动态调用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
会对任何更改进行回退
@echo off
setlocal enabledelayedexpansion
:::This part is not exactly necessary but it creates the file dictionary.txt and the var - this
echo.word>dictionary.txt
set this=notaword
:::So instead of checking for errorlevel just check for a space in the output
:middle
for /f "tokens=*" %%a in ('findstr /n /b /c:%this% dictionary.txt') do (
set "output=%%a"
goto :yeah
)
:yeah
if exist %output% (""," "
goto :oops
) else (
goto :nice
)
:oops
echo.%this% is NOT a word
pause & set this=word & goto :middle
:nice
echo.%output%
pause