在 Windows 批处理文件中设置错误级别

问题描述 投票:0回答:8

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

这是我的批处理脚本:

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帖子,我不确定这个问题是否相关

batch-file
8个回答
34
投票

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 if 命令扩展已启用,则它回退到ERRORLEVEL
ERRORLEVEL
更新%ERRORLEVEL%

Raymond Chen 有一篇很好的博客文章:

ERRORLEVEL is not %ERRORLEVEL%

。这个答案中的一些内容是无耻地从它那里抄来的。
    


12
投票
@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)

 中,整个块被解析并执行 
THEN。块中的任何%var%
都将被该变量的值替换
在块被解析时 - 在执行块之前。

因此,

IF (something) else (somethingelse)

 将使用遇到 
%variables%
 时的 
IF
 的值来执行。

克服此问题的两种常见方法是 1) 使用

setlocal enabledelayedexpansion

 并使用 
!var!
 代替 
%var%
 来访问 
var
 的更改值或 2) 调用子例程以使用更改后的值执行进一步处理.

因此请注意使用

CALL ECHO %%var%%

,它显示 
var
 的更改值。显示
CALL ECHO %%errorlevel%%
,但遗憾的是随后重置错误级别。
如果

IF DEFINED var

已定义为

CURRENTLY
,则
var 为 true。

ERRORLEVEL

是一个特殊的变量名。它由系统设置,但如果由用户设置,则用户分配的值会覆盖系统值。
如果

IF ERRORLEVEL n

是 n

 或大于 n
,则
errorlevel 为 TRUE。因此,IF ERRORLEVEL 0
 始终为真。

语法

SET "var=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

请注意,正如我之前提到的,副本只是

ECHO

 编辑的。

和输出.txt

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

4
投票
使用类似以下子例程的内容:

: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

所以,整个事情看起来像这样:

测试.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

通过.cmd 的东西...

DIR >nul 2>&1

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


4
投票
有一个简单的方法来设置

%errorlevel%

,这是我几年前学到的一个技巧:

:: force errorlevel to 1 @(call) echo %errorlevel% :: force errorlevel to 0 @(call ) echo %errorlevel% pause

call

 后面需要空格才能将 
%errorlevel%
 设置为 
0

更新:研究后,我找到了参考这里


2
投票
对于后代,当专门将其设置为0时,我喜欢

ver >nul
ver.exe 始终返回 0。


1
投票
对我来说,简单地使用

cmd /c exit 2

 就可以设置 
errorlevel
 并在批处理文件中本地使用它,甚至在它结束后询问外面的 
errorlevel

set errorlevel=2 : cmd /c exit %errorlevel% : if errorlevel 3 echo 3 if errorlevel 2 echo 2 if errorlevel 1 echo 1 if errorlevel 1 echo 0

结果

>test.bat 2 1 0 >if errorlevel 2 echo 2 2
    

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 ) ) )
    

0
投票
大多数答案并不适用于所有情况(即:xp、win9x...)

此行会将 ERRORLEVEL 设置为 1,适用于 DOS 或更高版本:

<nul find "" if errorlevel 1 echo ERRORLEVEL is 1 or more
此行会将 ERRORLEVEL 设置为 0,适用于 DOS 或更高版本:

echo a |find "a" >nul if errorlevel==0 echo No Error
    
© www.soinside.com 2019 - 2024. All rights reserved.