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.
我正在编写一个批处理脚本,该脚本将遍历文本文件的每一行,(每行包含一个文件名)检查该文件是否存在,然后运行该文件并移动它。
Here is my batch script:
这是我的批处理脚本:
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
)
Here is the output:
这是输出:
I do not understand why the "if errorlevel" is not working as expected... if the file does not exist (as in this example where it does not exist) it should NOT try to run the file, it should NOT copy the file, and it should echo a 2 not a 0
我不明白为什么“如果errorlevel”不能像预期的那样工作……如果文件不存在(如本例中不存在该文件),它不应该尝试运行该文件,它不应该复制该文件,它应该响应一个2而不是0。
Edit 1: I was reading another SO Post regarding "delayed environment variable expansion" I am not sure if this issue is related
编辑1:我正在阅读另一个关于“延迟环境变量扩展”的帖子,我不确定这个问题是否相关。
4 个解决方案
#1
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
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)
注意:输出。txt在开始时被删除,否则>>将附加到任何现有文件。如果删除失败,>nul会抑制错误消息。文件不存在)
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.
在一个块语句(一个圆括号的语句序列)中,整个块被解析,然后执行。在块被解析之前,块中的任何%var%将被该变量的值所替换——在该块被执行之前。
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.
两种常见的解决方法是使用setlocal enabledelayedexpansion和use !var!将%var%用于访问var或2的chnage值,以调用子例程以使用已更改的值执行进一步的处理。
Note therefore the use of CALL ECHO %%var%%
which displays the changed value of var
. CALL ECHO %%errorlevel%%
displays, but sadly then RESETS errorlevel.
因此,使用调用ECHO %%var%%,显示var的更改值。调用ECHO %%errorlevel%%显示,但遗憾的是重置errorlevel。
IF DEFINED var
is true if var
is CURRENTLY defined.
如果定义的var是正确的,如果var是当前定义的。
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.
ERRORLEVEL是一个特殊的varable名称。它由系统设置,但如果由用户设置,用户指定的值将覆盖系统值。
IF ERRORLEVEL n
is TRUE if errorlevel
is n OR GREATER THAN n. IF ERRORLEVEL 0
is therefore always true.
如果ERRORLEVEL是n或大于n,则ERRORLEVEL n为真,如果ERRORLEVEL 0始终为真。
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.
语法设置“var=value”(其中值可能为空)用于确保在指定的值中不包含一行末尾的任何散列空间。
The required commands are merely ECHO
ed for testing purposes. After you've verified that the commands are correct, change ECHO COPY
to COPY
to actually copy the files.
所需要的命令仅用于测试目的。在您验证了命令是否正确之后,将ECHO副本更改为副本以实际复制文件。
I used the following input.txt
:
我使用了下面的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
与现有的文件seterr *。蝙蝠含有
@ECHO OFF
EXIT /b 1
(where the 1
in the last line determines the errorlevel
returned)
(最后一行中的1确定返回的errorlevel)
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 ECHO
ed as I mentioned earlier.
请注意,该副本仅与我前面提到的相同。
and output.txt
和output.txt
seterr1.bat, J1, K1
seterr5.bat, J2, K2
seterr5.bat, J4, K4
notexist.bat, J5, K5
#2
16
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和%ERRORLEVEL%是两个不同的变量。这意味着带有echo return代码的代码是%errorlevel%,如果%errorlevel% neq0 >>输出。txt %%i, %%j, %%k可能是错误的。
ERRORLEVEL
is builtin and used to fetch the result of the last command. You can use it like:
ERRORLEVEL是builtin,用于获取最后一个命令的结果。你可以这样使用:
IF ERRORLEVEL 1 ECHO error level is 1 or more
ERRORLEVEL
cannot be set, just like bash does not let you set ?= ...
不能设置ERRORLEVEL,就像bash不让您设置一样?
%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%
.
%ERRORLEVEL%是一个环境变量。如果设置%ERRORLEVEL%,那么当您使用%ERRORLEVEL%时,它将在您的脚本中使用。如果没有设置%ERRORLEVEL%,如果启用了命令扩展,则返回到ERRORLEVEL。ERRORLEVEL不更新%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.
Raymond Chen有一个很好的博客条目:ERRORLEVEL不是%ERRORLEVEL%。这个答案中的一些内容被无耻地剽窃了。
#3
2
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...
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...
somethingthatfails.cmd……
DIR some command that fails >nul 2>&1
somethingthatpasses.cmd...
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.
这其中的一个副作用是一个名为ret.cmd的文件。我通常使用:完成清理并删除它的结束子例程。
#4
0
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.
这是设计来执行%%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
)
)
)
#1
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
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)
注意:输出。txt在开始时被删除,否则>>将附加到任何现有文件。如果删除失败,>nul会抑制错误消息。文件不存在)
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.
在一个块语句(一个圆括号的语句序列)中,整个块被解析,然后执行。在块被解析之前,块中的任何%var%将被该变量的值所替换——在该块被执行之前。
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.
两种常见的解决方法是使用setlocal enabledelayedexpansion和use !var!将%var%用于访问var或2的chnage值,以调用子例程以使用已更改的值执行进一步的处理。
Note therefore the use of CALL ECHO %%var%%
which displays the changed value of var
. CALL ECHO %%errorlevel%%
displays, but sadly then RESETS errorlevel.
因此,使用调用ECHO %%var%%,显示var的更改值。调用ECHO %%errorlevel%%显示,但遗憾的是重置errorlevel。
IF DEFINED var
is true if var
is CURRENTLY defined.
如果定义的var是正确的,如果var是当前定义的。
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.
ERRORLEVEL是一个特殊的varable名称。它由系统设置,但如果由用户设置,用户指定的值将覆盖系统值。
IF ERRORLEVEL n
is TRUE if errorlevel
is n OR GREATER THAN n. IF ERRORLEVEL 0
is therefore always true.
如果ERRORLEVEL是n或大于n,则ERRORLEVEL n为真,如果ERRORLEVEL 0始终为真。
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.
语法设置“var=value”(其中值可能为空)用于确保在指定的值中不包含一行末尾的任何散列空间。
The required commands are merely ECHO
ed for testing purposes. After you've verified that the commands are correct, change ECHO COPY
to COPY
to actually copy the files.
所需要的命令仅用于测试目的。在您验证了命令是否正确之后,将ECHO副本更改为副本以实际复制文件。
I used the following input.txt
:
我使用了下面的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
与现有的文件seterr *。蝙蝠含有
@ECHO OFF
EXIT /b 1
(where the 1
in the last line determines the errorlevel
returned)
(最后一行中的1确定返回的errorlevel)
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 ECHO
ed as I mentioned earlier.
请注意,该副本仅与我前面提到的相同。
and output.txt
和output.txt
seterr1.bat, J1, K1
seterr5.bat, J2, K2
seterr5.bat, J4, K4
notexist.bat, J5, K5
#2
16
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和%ERRORLEVEL%是两个不同的变量。这意味着带有echo return代码的代码是%errorlevel%,如果%errorlevel% neq0 >>输出。txt %%i, %%j, %%k可能是错误的。
ERRORLEVEL
is builtin and used to fetch the result of the last command. You can use it like:
ERRORLEVEL是builtin,用于获取最后一个命令的结果。你可以这样使用:
IF ERRORLEVEL 1 ECHO error level is 1 or more
ERRORLEVEL
cannot be set, just like bash does not let you set ?= ...
不能设置ERRORLEVEL,就像bash不让您设置一样?
%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%
.
%ERRORLEVEL%是一个环境变量。如果设置%ERRORLEVEL%,那么当您使用%ERRORLEVEL%时,它将在您的脚本中使用。如果没有设置%ERRORLEVEL%,如果启用了命令扩展,则返回到ERRORLEVEL。ERRORLEVEL不更新%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.
Raymond Chen有一个很好的博客条目:ERRORLEVEL不是%ERRORLEVEL%。这个答案中的一些内容被无耻地剽窃了。
#3
2
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...
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...
somethingthatfails.cmd……
DIR some command that fails >nul 2>&1
somethingthatpasses.cmd...
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.
这其中的一个副作用是一个名为ret.cmd的文件。我通常使用:完成清理并删除它的结束子例程。
#4
0
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.
这是设计来执行%%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
)
)
)