[英]ERRORLEVEL in FOR /F Command Loop Returns Unexpected Result
我正在嘗試記錄net stop
的輸出,同時還捕獲其ERRORLEVEL
。
基於這個問題,我在嵌套子程序中嘗試了以下操作:
set /a loopIndex=0
for /F "usebackq delims=" %%i in (`net stop %SERVICE_NAME%`) do (
if !loopIndex! EQU 0 if !errorlevel! EQU 1 set statementError=1
set /a loopIndex+=1
call :logMessage "%%i"
)
echo statementError: %statementError%
但是,這不起作用,即使net stop
成功也會拋出1
。
如果沒有臨時文件,這可能嗎? 如果沒有,臨時文件解決方案會是什么樣子?
正如@drruruu 在這個問題中所問的:
如果沒有臨時文件,這可能嗎?
是的,沒有臨時文件也是可能的。 通過將 ERRORLEVEL 發送到 IN 子句中的 STDOUT 並在 LOOP 子句中解析它。 它也可以通過延遲擴展來完成。
為方便起見,這里有一個例子。 它有點像 FINDSTR 包裝器,用於在批處理本身中搜索字符串。 它涵蓋了您需要知道哪里出了問題、哪里出了問題以及為什么出了問題的所有常見情況:
以下腳本使用 FINDSTR 和標志作為參數模擬這些情況:
@echo off
SETLOCAL ENABLEEXTENSIONS
IF ERRORLEVEL 1 (
ECHO Can't use extensions
EXIT /B 1
)
SETLOCAL ENABLEDELAYEDEXPANSION
IF ERRORLEVEL 1 (
ECHO Can't use delayed expansion
EXIT /B 1
)
REM The string to search
SET "LOCALV_STRING=%1"
REM The file to search. Myself.
SET "LOCALV_THIS=%0"
REM Store the exit code for the LOOP
SET "LOCALV_ERR="
REM Store the exit code for the IN
SET "LOCALV_RET="
REM Flag to stop parsing output for error simulation
SET "LOCALV_END="
REM To get the exit code of the IN clause, we get it through expansion with a second FOR loop using the well known CALL expansion and send it on STDOUT in the form "__<code>"
FOR /F "%~3tokens=*" %%M IN ('FINDSTR "!LOCALV_STRING!" "!LOCALV_THIS%~4!" ^
^& FOR /F %%A IN ^("ERRORLEVEL"^) DO @CALL ECHO __%%%%A%%') DO (
SET "LOCALV_TMP=%%~M"
REM Simulate that something goes wrong with FINDSTR I/O
IF NOT EXIST "!LOCALV_THIS!%~4" (
SET "LOCALV_RET=255"
SET LOCALV_END=1
)
IF "!LOCALV_END!" == "" (
REM SImulate a problem in the loop
IF "%2" == "1" (
(CMD /C EXIT /B 127)
SET LOCALV_END=1
) ELSE (
IF NOT "!LOCALV_TMP:~0,2!" == "__" ECHO Found: !LOCALV_TMP!
)
)
IF "!LOCALV_TMP:~0,2!!LOCALV_RET!" == "__" SET "LOCALV_RET=!LOCALV_TMP:__=!"
)
SET "LOCALV_ERR=!ERRORLEVEL!"
REM LOCALV_ERR get the exit code from the last iteration of the for loop
REM LOCALV_RET get the exit code from the IN command of the for loop
REM Sadly, FINDSTR exit with 1 if it did not find the string, but also with 1 if it could not found the file. To simulate a proper handling of exit code for
REM abnormal hardware/software situation, %2 is used to force a 255 exit code
REM If LOCALV_RET is not defined, this means the FOR...ECHO__.. wasn't executed, therefore there is a pb with the FOR LOOP
IF "!LOCALV_RET!" == "" (
ECHO Something went wrong with FOR...
EXIT /B 1
)
REM If LOCALV_RET is defined, this means the FOR...ECHO__.. was executed and the last loop operation has parsed the FINDSTR exit code, LOCALV_RET get its exit code
REM If LOCALV_RET is defined but LOCALV_ERR is not "0", something went wrong in the loop (I/O error, out of memory, wathever you could think), the problem is not FINDSTR
IF NOT "!LOCALV_ERR!" == "0" (
ECHO Error in the loop while searching "!LOCALV_STRING!" in "!LOCALV_THIS!", exit code !LOCALV_RET!. Loop exit code : !LOCALV_ERR!.
EXIT /B 4
)
REM If LOCALV_RET is "0", FINDSTR got matching strings in the file, if "1", FINDSTR don't find any matching string, if anything else, FINDSTR got a problem like failed I/O.
REM If LOCALV_RET is "0" and LOCALV_ERR is "0", everything is ok.
IF "!LOCALV_RET!" == "0" (
ECHO Success.
EXIT /B 0
)
REM If LOCALV_RET is "1" and LOCALV_ERR is "0", FINDSTR failed to find the string in the file "or" failed to find file, for the latter we simulate that FINDSTR exit with 255 .
IF "!LOCALV_RET!" == "1" (
ECHO FINDSTR failed to find "!LOCALV_STRING!" in "!LOCALV_THIS!", exit code !LOCALV_RET!. Loop exit code : !LOCALV_ERR!.
EXIT /B 2
)
REM If LOCALV_RET isn't "0" nor "1" and LOCALV_ERR is "0", FINDSTR failed to do the job and LOCALV_RET got the exit code.
ECHO FINDSTR: Houst^W OP, we've got a problem here while searching "!LOCALV_STRING!" in "!LOCALV_THIS!", exit code !LOCALV_RET!. Loop exit code : !LOCALV_ERR!.
EXIT /B 3
腳本輸出:
PROMPT>.\for.bat FOR 0 "" ""
Found: FOR /F "%~3tokens=*" %%M IN ('FINDSTR "FOR" ""
Found: ^& FOR /F %%A IN ^("ERRORLEVEL"^) DO @CALL ECHO __%%%%A%%') DO (
Found: REM If LOCALV_RET is not defined, this means the FOR...ECHO__.. wasn't executed, therefore there is a pb with the FOR LOOP
Found: ECHO Something went wrong with FOR...
Found: REM If LOCALV_RET is defined, this means the FOR...ECHO__.. was executed and the last loop operation has parsed the FINDSTR exit code, LOCALV_RET get its exit code
Success.
PROMPT>.\for.bat ZZZ 0 "" ""
FINDSTR failed to find "ZZZ" in ".\for.bat", exit code 1. Loop exit code : 0.
PROMPT>.\for.bat FOR 1 "" ""
Error in the loop while searching "FOR" in ".\for.bat", exit code 0. Loop exit code : 127.
PROMPT>.\for.bat FOR 0 "delims" ""
delimstokens=*" was unexpected.
Something went wrong with FOR...
PROMPT>.\for.bat FOR 1 "" "ERR"
FINDSTR : Can't open
FINDSTR: HoustW OP, we've got a problem here while searching "FOR" in ".\for.bat", exit code 255. Loop exit code : 0.
FOR /F 命令在新的 cmd.exe 進程中執行 NET STOP。 FOR /F 處理標准輸出,僅此而已。 主腳本無法看到 FOR /F 命令可能創建的任何變量值,因為一旦子進程終止,它們就會消失。
最簡單和最有效的解決方案使用臨時文件。 我假設 NET STOP 有兩種可能的錯誤代碼 - 成功 = 0 和錯誤 = 1。因此,最簡單的解決方案是在出現錯誤時簡單地創建一個臨時錯誤信號文件。
下面以一種通用的方式演示了這個概念:
@echo off
del error.flag 2>nul
for /f "delims=" %%A in ('net stop %SERVICE_NAME% ^|^| echo error>error.flag') do (
...
)
if exist error.flag (
echo There was an error
del error.flag
)
如果需要,您可以輕松地將錯誤測試放在 DO() 代碼中。
雖然@dbenham 的答案適用於%ERRORLEVEL%
返回二進制值的情況,但我無法確認或否認返回的net stop
退出代碼實際上是二進制的,因此選擇了 n 進制解決方案。
根據@dbenham 的DOS 提示論壇帖子:
FOR /F "delims=" %%i IN ('net stop MyService 2^>^&1 ^& CALL ECHO %%^^ERRORLEVEL%%^>error.level') DO (
CALL :logMessage "%%i"
)
FOR /F "delims=" %%i IN (error.level) DO (SET /A statementError=%%i)
DEL error.level
IF %statementError% NEQ 0 ()
分解語句解析:
net stop MyService 2^>^&1 ^& CALL ECHO %%^^ERRORLEVEL%%^>error.level
net stop MyService 2>&1 & CALL ECHO %^ERRORLEVEL%>error.level
echo %ERRORLEVEL%>error.level
在這里, CALL
專門用於延遲解析%ERRORLEVEL%
直到執行ECHO
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.