首页 文章

在Windows批处理文件中设置errorlevel

提问于
浏览
15

我正在编写一个批处理脚本,它将循环遍历文本文件的每一行(每行包含一个文件名),检查文件是否存在,然后运行该文件并移动它 .

这是我的批处理脚本:

REM Loop through each line of input.txt
FOR /F "tokens=1-3 delims=, " %%i IN (./ready/input.txt) DO (
  ECHO.
  ECHO.
  ECHO.
  ECHO Check %%i exists, set error flag if it doesnt
  if not exist .\ready\%%i set errorlevel=2
echo return code is %errorlevel%

  ECHO Run %%i if it exists
  if errorlevel 0 call .\ready\%%i

  ECHO Move %%i to archive if no error occured 
  if errorlevel 0 copy .\ready\%%i .\archive\%mydate%_%mytime%_%%j_%%k_%%i

  ECHO Copy line of text to the new output.txt file if an error occured
  if %errorlevel% NEQ 0 >>output.txt %%i, %%j, %%k
)

这是输出:
enter image description here

我不明白为什么“如果errorlevel”没有按预期工作...如果文件不存在(如在这个例子中它不存在)它不应该尝试运行该文件,它不应该复制文件,它应该回显2而不是0

Edit 1 :我正在阅读SO Post关于"delayed environment variable expansion"我不确定这个问题是否相关

4 回答

  • 8
    @ECHO OFF
    SETLOCAL
    DEL output.txt 2>nul
    REM Loop through each line of input.txt
    FOR /F "tokens=1-3 delims=, " %%i IN (.\ready\input.txt) DO (
      ECHO.
      ECHO.
      ECHO.
      ECHO Check %%i exists, set error flag if it doesnt
      if exist .\ready\%%i (set "errorflag=") ELSE (set errorflag=2)
    CALL echo return code is %%errorflag%%
    
      ECHO Run %%i if it exists
      if NOT DEFINED errorflag (
       call .\ready\%%i
       ECHO Move %%i to archive if no error occured
       if errorlevel 1 (SET errorflag=3) ELSE (ECHO copy .\ready\%%i .\archive\%mydate%_%mytime%_%%j_%%k_%%i)
      )
      ECHO Copy line of text to the new output.txt file if an error occured
      if DEFINED errorflag >>output.txt ECHO %%i, %%j, %%k
    )
    GOTO :EOF
    

    这是一个重写的程序 .

    注意: output.txt 在开始时被删除,否则 >> 将附加到任何现有文件 . 2>nul 如果删除失败(例如文件不存在),则会抑制错误消息

    在块语句 (a parenthesised series of statements) 中,解析ENTIRE块并执行 THEN . 在块执行之前,块中的任何_844785都将被该变量的值 AT THE TIME THE BLOCK IS PARSED 替换 .

    因此, IF (something) else (somethingelse) 将在遇到 IF 时使用 %variables% 的值执行 .

    解决此问题的两种常用方法是1)使用 setlocal enabledelayedexpansion 并使用 !var! 代替 %var% 来访问 var 或2的中间值,以调用子例程以使用更改的值执行进一步处理 .

    因此请注意 CALL ECHO %%var%% 的使用,它显示 var 的更改值 . CALL ECHO %%errorlevel%% 显示,但遗憾的是RESETS错误级别 .

    如果 varCURRENTLY ,则 IF DEFINED var 为真 .

    ERRORLEVEL 是一个特殊的可变形名称 . 它由系统设置,但如果由用户设置,则用户指定的值将覆盖系统值 .

    如果 errorlevel 是n OR GREATER THAN n ,则 IF ERRORLEVEL n 为TRUE . IF ERRORLEVEL 0 因此总是如此 .

    语法 SET "var=value" (其中value可以为空)用于确保行末尾的任何杂散空格不包含在指定的值中 .

    所需命令仅用于测试目的 . 在确认命令正确后,将 ECHO COPY 更改为 COPY 以实际复制文件 .

    我使用了以下 input.txt

    seterr1.bat, J1, K1
    seterr5.bat,J2,K2
    seterr0.bat,J3 K3
    seterr5.bat, J4, K4
    notexist.bat, J5, K5
    

    使用包含的现有文件 seterr*.bat

    @ECHO OFF
    EXIT /b 1
    

    (最后一行中的 1 确定 errorlevel 返回)

    并收到结果输出:

    Check seterr1.bat exists, set error flag if it doesnt
    return code is 
    Run seterr1.bat if it exists
    Move seterr1.bat to archive if no error occured
    Copy line of text to the new output.txt file if an error occured
    
    Check seterr5.bat exists, set error flag if it doesnt
    return code is 
    Run seterr5.bat if it exists
    Move seterr5.bat to archive if no error occured
    Copy line of text to the new output.txt file if an error occured
    
    Check seterr0.bat exists, set error flag if it doesnt
    return code is 
    Run seterr0.bat if it exists
    Move seterr0.bat to archive if no error occured
    copy .\ready\seterr0.bat .\archive\__J3_K3_seterr0.bat
    Copy line of text to the new output.txt file if an error occured
    
    Check seterr5.bat exists, set error flag if it doesnt
    return code is 
    Run seterr5.bat if it exists
    Move seterr5.bat to archive if no error occured
    Copy line of text to the new output.txt file if an error occured
    
    Check notexist.bat exists, set error flag if it doesnt
    return code is 2
    Run notexist.bat if it exists
    Copy line of text to the new output.txt file if an error occured
    

    请注意,COPY仅仅是我之前提到过的 .

    和output.txt

    seterr1.bat, J1, K1
    seterr5.bat, J2, K2
    seterr5.bat, J4, K4
    notexist.bat, J5, K5
    
  • 0

    ERRORLEVEL%ERRORLEVEL% 是两个不同的变量 . 这意味着您的代码 echo return code is %errorlevel%if %errorlevel% NEQ 0 >>output.txt %%i, %%j, %%k 可能是错误的 .

    ERRORLEVEL 是内置的,用于获取最后一个命令的结果 . 您可以像以下一样使用它:

    IF ERRORLEVEL 1 ECHO error level is 1 or more
    

    ERRORLEVEL 无法设置,就像bash不会让你 set ?= ...

    %ERRORLEVEL% 是一个环境变量 . 如果设置了 %ERRORLEVEL% ,则在使用 %ERRORLEVEL% 时在脚本中使用它 . 如果 %ERRORLEVEL% 未设置 AND 如果启用了命令扩展,则它将回退到 ERRORLEVEL . ERRORLEVEL 不更新 %ERRORLEVEL% .

    Raymond Chen有一篇很好的博客文章:ERRORLEVEL is not %ERRORLEVEL% . 这个答案中的一些内容是无耻地从中解脱出来的 .

  • 2

    使用类似以下子例程的东西:

    :return
       ECHO @exit /b %1 >ret.cmd
       CALL ret.cmd
       GOTO :eof
    

    然后像这样使用它:

    :Attempt
       SETLOCAL
       CALL somethingThatFails
       SET retcode=!errorlevel!
       CALL somethingThatPasses : don't care about the errorlevel here
       CALL :return !retcode!
       ENDLOCAL
       CALL :eof
    

    所以,整件事情会像以下一样:

    TEST.CMD ...

    @ECHO OFF
    
    SETLOCAL ENABLEDELAYEDEXPANSION
    
    CALL :Attempt
    IF !errorlevel! NEQ 0 (ECHO Attempt Failed) ELSE (ECHO Attempt succeeded!)
    GOTO :eof
    
    :Attempt
       SETLOCAL
       CALL somethingThatFails
       SET retcode=!errorlevel!
       CALL somethingThatPasses : don't care about the errorlevel here
       CALL :return %retcode%
       ENDLOCAL
       CALL :eof
    
    :return
       ECHO @exit /b %1 >return.cmd
       CALL ret.bat
       GOTO :eof
    

    somethingthatfails.cmd ...

    DIR some command that fails >nul 2>&1
    

    somethingthatpasses.cmd ...

    DIR >nul 2>&1
    

    这样做的一个副作用是放置一个名为ret.cmd的文件 . 我通常使用:end子例程进行清理并删除它 .

  • 21

    这被设计为仅在存在时执行%% i项目并且检查错误并移动或记录 . 如果%% i项不存在则它将不执行任何操作 .

    REM Loop through each line of input.txt
    FOR /F "tokens=1-3 delims=, " %%i IN (.\ready\input.txt) DO (
      ECHO.
      ECHO.
      ECHO.
      ECHO Check %%i exists, execute it if it does
      if exist .\ready\%%i (
        call .\ready\%%i
        ECHO Move %%i to archive if no error occured 
        if not errorlevel 1 (
            copy .\ready\%%i .\archive\%mydate%_%mytime%_%%j_%%k_%%i
          ) else (
            ECHO Copy line of text to the new output.txt file if an error occurred
            >>output.txt %%i, %%j, %%k
          )
      )
    )
    

相关问题