Set errorlevel in Windows batch file

后端 未结 4 947
情书的邮戳
情书的邮戳 2021-02-04 04:47

I am writing a batch script that will loop through each line of a text file, (each line containing a filename) check if the file exists and then runs the file and moves it.

相关标签:
4条回答
  • 2021-02-04 05:14

    Use something like the following subroutine:

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

    Then use it like this:

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

    So, the whole thing would looke something like:

    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
    

    The one side effect of this is a file laying around called ret.cmd. I usually use an :end subroutine that does cleanup and would delete it.

    0 讨论(0)
  • 2021-02-04 05:23
    @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
    

    Here's a rewritten procedure.

    Note: output.txt is deleted at the start, else the >> would append to any existing file. 2>nul suppresses error messages if the delete fails (eg. file not exist)

    Within a block statement (a parenthesised series of statements), the ENTIRE block is parsed and THEN executed. Any %var% within the block will be replaced by that variable's value AT THE TIME THE BLOCK IS PARSED - before the block is executed.

    Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.

    Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the chnaged value of var or 2) to call a subroutine to perform further processing using the changed values.

    Note therefore the use of CALL ECHO %%var%% which displays the changed value of var. CALL ECHO %%errorlevel%% displays, but sadly then RESETS errorlevel.

    IF DEFINED var is true if var is CURRENTLY defined.

    ERRORLEVEL is a special varable name. It is set by the system, but if set by the user, the user-assigned value overrides the system value.

    IF ERRORLEVEL n is TRUE if errorlevel is n OR GREATER THAN n. IF ERRORLEVEL 0 is therefore always true.

    The syntax SET "var=value" (where value may be empty) is used to ensure that any stray spaces at the end of a line are NOT included in the value assigned.

    The required commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO COPY to COPY to actually copy the files.

    I used the following input.txt:

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

    With existing files seterr*.bat which contain

    @ECHO OFF
    EXIT /b 1
    

    (where the 1 in the last line determines the errorlevel returned)

    and received the resultant output:

    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
    

    Note that the COPY is merely ECHOed as I mentioned earlier.

    and output.txt

    seterr1.bat, J1, K1
    seterr5.bat, J2, K2
    seterr5.bat, J4, K4
    notexist.bat, J5, K5
    
    0 讨论(0)
  • 2021-02-04 05:30

    This is designed to execute the %%i item only if it exists and follow through with checking for errors and move or log. if the %%i item doesn't exist then it will do nothing.

    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
          )
      )
    )
    
    0 讨论(0)
  • 2021-02-04 05:35

    ERRORLEVEL and %ERRORLEVEL% are two different variables. That means your code with echo return code is %errorlevel% and if %errorlevel% NEQ 0 >>output.txt %%i, %%j, %%k is probably wrong.

    ERRORLEVEL is builtin and used to fetch the result of the last command. You can use it like:

    IF ERRORLEVEL 1 ECHO error level is 1 or more
    

    ERRORLEVEL cannot be set, just like bash does not let you set ?= ...

    %ERRORLEVEL% is an environmental variable. If %ERRORLEVEL% is set, then its used in your script when you use %ERRORLEVEL%. If %ERRORLEVEL% is not set AND if command extensions are enabled, then it falls back to ERRORLEVEL. ERRORLEVEL does not update %ERRORLEVEL%.

    Raymond Chen has a good blog entry on it: ERRORLEVEL is not %ERRORLEVEL%. Some of the content in this answer was shamelessly lifted from it.

    0 讨论(0)
提交回复
热议问题