我正在编写一个批处理脚本,它将循环遍历文本文件的每一行(每行包含一个文件名),检查文件是否存在,然后运行该文件并移动它。
这是我的批处理脚本:
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
)
这是输出:
我不明白为什么“if errorlevel”没有按预期工作...如果文件不存在(如本例所示,它不存在)它不应该尝试运行该文件,它不应该复制文件,它应该回显2而不是0
编辑1 :我正在阅读关于“延迟环境变量扩展”的另一个SO Post我不确定此问题是否相关
答案 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 ,如果启用了命令扩展,那么将回退到ERRORLEVEL
。 ERRORLEVEL
不更新%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%%
更改值的var
。 CALL 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
)
)
)