我想我对ERRORLEVEL和%ERRORLEVEL%有基本的了解但是!ERRORLEVEL!困惑我。
我正在编写一个调用可执行文件的脚本,然后编写任务列表以查看其是否正在运行,然后taskkill将其杀死,如果是,然后尝试输出错误级别并重复其他exe文件,我意识到我真的不知道理解错误级别。
我设置一个等于!errorlevel的变量! 然后在回显中使用没有引号的变量,并且当集合之后发生错误时变量从一个uint16变为另一个uint16,就像它对真实变量而不是副本的引用一样。我要复制。有人可以解释这些人之间的区别吗?
更新: 这是我正在研究的片段。
for %%P in (%executableList%) do (
echo ----------------------------------------------------------------------------------
set exeErrorlevel=0
set running=false
start %%~fP
set exeErrorlevel=!ERRORLEVEL!
rem for debugging purposes
echo %%~nP%%~xP older errorlevel %ERRORLEVEL%
echo %%~nP%%~xP newer errorlevel !ERRORLEVEL!
echo before tasklist running var is : !running!
tasklist /FI "IMAGENAME eq %%~fP" | find /I /N /C "%%~fP" >nul && set running=true
echo after tasklist is running var is: !running!
if !running! equ true (
echo %%~nP%%~xP Program is running
taskkill /F /IM %%~nP%%~xP /T
echo %%~nP%%~xP Program was killed
if !exeErrorlevel! == 0 (
echo %passString% %%~nP%%~xP process was started and killed safely
echo %passString% %%~nP%%~xP process was started and killed safely >>%outputfile%
) else (
echo %failString% %%~nP%%~xP process was killed with errorcode !exeErrorlevel!
echo %failString% %%~nP%%~xP process was killed with errorcode !exeErrorlevel! >>%outputfile%
)
) else (
if !exeErrorlevel! == 0 (
echo %passString% %%~nP%%~xP process exited safely
echo %passString% %%~nP%%~xP process exited safely >>%outputfile%
) else (
taskkill /F /IM %%~nP%%~xP /T
echo %failString% %%~nP%%~xP process abruptly exited with errorcode !exeErrorlevel!
echo %failString% %%~nP%%~xP process abruptly exited with errorcode !exeErrorlevel! >>%outputfile%
)
)
echo. >>%outputfile%
)
我需要确保exeErrorlevel在某个时间点有一个errorlevel的副本 - 我只想从exe中捕获错误,而不是从tasklist / find / taskill的成功/失败中捕获错误。我担心exeerrorlevel因为延迟扩展而在执行时访问延迟的错误级别。也许应该设置exeErrorlevel =%errorlevel%而不是。在回显较旧和较新变量的行中,通常返回不同的整数?在我的所有测试运行中,%errorlevel%似乎通常返回0而!errorlevel!对于退出代码错误的可执行文件,它始终为零。
答案 0 :(得分:4)
错误级别
errorlevel
是一个动态变量的名称(它不放在环境块中但保留在内存中),它存储上一个执行的进程/命令的退出代码(如果它设置了该值,则为{ {3}},here,here和here)。
if
命令允许使用if errorlevel n
语法检查errorlevel
变量的值是否大于或等于n
,而不涉及批处理解析器检索变量的值。
但是,如果我们让批处理解析器使用变量值,%errorlevel%
只是对存储在变量中的值的引用,即读操作。与!errorlevel!
相同。两者之间的主要区别是 时检索值取决于变量扩展的here。
使用if errorlevel
或检索变量中的值有很大的不同:
if
构造不会进行此测试。 如果您执行set errorlevel=10
之类的操作,则不会使用errorlevel
或%errorlevel%
检索动态!errorlevel!
值,因为环境中设置的值将隐藏动态值。但由于if errorlevel
不读取环境块但直接读取保存该值的内部变量,因此它可以正常工作。
变量
批处理语法不包括让多个变量指向内存中相同值的选项,如果其中一个变量更改其值,另一个将反映更改。
可以通过正确使用变量扩展中的不同阶段,将变量正确设置为另一个变量的名称来模拟此行为,并强制批处理解析器对命令执行两次传递,以便将第一个变量解析为第二,那是真正的价值。
您的问题
仅用于分析的简化(非均匀工作)代码
1 for %%P in (%executableList%) do (
2
3 start %%~fP
4 set exeErrorlevel=!ERRORLEVEL!
5
6 echo %%~nP%%~xP older errorlevel %ERRORLEVEL%
7 echo %%~nP%%~xP newer errorlevel !ERRORLEVEL!
8 ....
9 if !running! equ true (
10 taskkill /F /IM %%~nP%%~xP /T
11 if !exeErrorlevel! == 0 (
12 ....
13 ) else (
14 echo process killed with errorcode !exeErrorlevel!
15 )
16 ) else (
17 if !exeErrorlevel! == 0 (
18 ....
19 ) else (
20 taskkill /F /IM %%~nP%%~xP /T
21 echo process abruptly exited with errorcode !exeErrorlevel!
22 )
23 )
第1行:解析do
子句中的代码,即所有代码。从代码中删除任何%var%
变量读取操作,在开始执行之前用变量内的值替换。这意味着如果变量更改其值,您将无法检索更改的值,因为读操作不存在,只有变量中的初始值。
第3行:可执行文件在单独的进程中启动,无需等待进程结束。那很重要么?见下一行
第4行:检索errorlevel
变量的当前(使用的延迟扩展)值并将其存储在exeErrorlevel
变量中。但是存储的值不是可执行文件返回的errorlevel
(单独的进程,不等待它结束,我们将如何知道exit code = errorlevel
是什么?),但{{1}的退出代码1}}命令。
第6行:当start
读取操作被删除时,该行将在%errorlevel%
子句开始执行之前回显存储在errorlevel
变量中的值。
第7行:检索do
变量的当前值。在这里,我们可以遇到问题。如何命名正在执行的脚本? errorlevel
和.bat
之间存在差异。成功时,如果这是.cmd
文件,则第4行中的set
命令将清除(设置为0)errorlevel
变量,但如果是.cmd
,则不会更改errorlevel
一个.bat
文件。
第11,14,21行:如exeErrorlevel
变量所示,它不包含有效值。不,将行更改为!errorlevel!
将不会检索流程的退出代码,而是检索taskkill
的退出代码。
为了能够检索进程的退出代码/错误级别,我们需要等待它结束。如果你需要启动进程,如果它继续运行kill它,并且在两种情况下检索退出代码,直接调用可执行文件或使用start "" /wait programName
,并行运行查杀过程(例如{{1}在启动程序之前或类似的东西)。主进程将等待并检索退出代码。监控进程处理查杀。