[英]Windows Batch: findstr not setting ERRORLEVEL within a for loop
誰能向我解釋以下代碼段為何打印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的新手,因此這對我來說有點神秘,因為這兩個語句似乎無關。 任何幫助,將不勝感激,謝謝!
問題在於,在code block
(帶括號的語句系列)中,任何%var%
都將在parse time
由變量的實際值替換。
在您的第一個示例中, %errorlevel%
0
並以此類推。 在第二個示例中,當遇到for
時為1
,因此將其替換為1
。
如果要顯示可能在循環中更改的環境變量的值,則需要執行以下三種操作之一:
調用setlocal enabledelayedexpansion
並回顯!var!
而不是%var%
-注意您可以激活的嵌套setlocal
指令的數量是有限的。
調用子程序
使用語法漏洞。
關於SO的delayedexpansion
文章很多。
粗略地講,您可以簡單地使用(注意-批處理中的大小寫基本上無關緊要,除了循環控制變量的情況( 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!
)
另一種方法是動態調用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
的run-time
時值,並且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
請注意, 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%%
)
更新:
如果在for語句的)
結束echo %ERRORLEVEL%
之后放置echo %ERRORLEVEL%
語句,則它會按預期工作。
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語句成功,因此它輸出具有匹配項的行(唯一傳遞給它的行):
C:\>echo blahbin | findstr bin
blahbin
C:\>echo %errorlevel%
0 ; success / found it..
雖然此語句不成功(findstr不輸出任何內容),並且錯誤級別設置為1:
C:\>echo blah_in | findstr bin
C:\>echo %errorlevel%
1 ; failed
@echo off
setlocal ENABLEDELAYEDEXPANSION
for /f %%i in ('cmd /c echo blah') do (
echo %%i | findstr bin > NUL
echo !ERRORLEVEL!
)
這應該工作。
cmd中的for循環從技術上講是一行,因此該變量僅擴展一次。 使用感嘆號代替百分號和“ ENABLEDELAYEDEXPANSION”應該可以解決它。
@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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.