在Windows批处理文件中设置errorlevel

时间:2014-01-02 22:11:21

标签: batch-file

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

这是我的批处理脚本:

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

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

编辑1 :我正在阅读关于“延迟环境变量扩展”的另一个SO Post我不确定此问题是否相关

4 个答案:

答案 0 :(得分:23)

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 ,如果启用了命令扩展,那么回退到ERRORLEVELERRORLEVEL 更新%ERRORLEVEL%

Raymond Chen有一篇很好的博客文章:ERRORLEVEL is not %ERRORLEVEL%。这个答案中的一些内容被无耻地解除了。

答案 1 :(得分:9)

@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 。在块执行之前,块中的任何%var%将被该变量的值在块被分配的时间替换。

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

要克服此问题的两种常见方法是:1)使用setlocal enabledelayedexpansion并使用!var!代替%var%来访问var或2的中间值以进行调用一个子程序,用于使用更改的值执行进一步处理。

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

如果IF DEFINED var 当前已定义,则

var为真。

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

如果IF ERRORLEVEL n为n 或大于n ,则

errorlevel为TRUE。因此IF ERRORLEVEL 0总是如此。

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

所需命令仅用于ECHO以用于测试目的。在您确认命令正确无误后,将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仅仅是我之前提到的ECHO

和output.txt

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

答案 2 :(得分: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子程序进行清理并删除它。

答案 3 :(得分:0)

这仅用于执行%% 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
      )
  )
)