我想我对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!对于退出代码错误的可执行文件,始终为非零 .
1 回答
错误级别
errorlevel
是动态变量的名称(它不放在环境块中但保留在内存中),它存储上一个执行的进程/命令的退出代码(如果它设置了该值,则读取here,here,here和here) .if
命令允许使用if errorlevel n
语法检查errorlevel
变量的值是否大于或等于n
,而不涉及批处理解析器检索变量的值 .但是,如果我们让批处理解析器使用变量值,
%errorlevel%
只是对存储在变量中的值的引用,即读操作 . 和!errorlevel!
一样 . 两者之间的主要区别是 when ,根据变量扩展的rules检索该值 .使用
if errorlevel
或检索变量中的值有很大的不同:变量读取操作将检查环境块是否包含具有指示名称的变量 .
if
构造不会进行此测试 .如果执行
set errorlevel=10
之类的操作,则不会使用%errorlevel%
或!errorlevel!
检索动态errorlevel
值,因为环境中设置的值将隐藏动态值 . 但由于if errorlevel
不读取环境块但直接读取保存该值的内部变量,因此它可以正常工作 .变量
批处理语法不包括让多个变量指向内存中相同值的选项,如果其中一个变量更改其值,另一个将反映更改 .
可以通过在变量扩展中正确使用不同的阶段,将变量正确设置为另一个的名称并强制批处理解析器对命令执行两次传递来模拟此行为,因此第一个变量被解析为第二个的名称,并且真正的 Value .
你的问题
简化(非均匀工作)代码仅用于分析
第1行:解析所有代码中
do
子句中的代码 . 从代码中删除任何%var%
变量读取操作,在开始执行之前用变量内的值替换 . 这意味着如果变量更改其值,您将无法检索更改的值,因为读操作不存在,只有变量中的初始值 .第3行:可执行文件在单独的进程中启动,无需等待进程结束 . 那很重要么?见下一行
第4行:检索
errorlevel
变量的当前(使用的延迟扩展)值并将其存储在exeErrorlevel
变量中 . 但是存储的值不是可执行文件返回的errorlevel
(单独的进程,不等待它结束,我们怎么知道exit code = errorlevel
是什么?),而是start
命令的退出代码 .第6行:当
%errorlevel%
读取操作被删除时,该行将在do
之前回显errorlevel
变量中存储的值子句开始执行 .第7行:检索
errorlevel
变量的当前值 . 在这里,我们可以遇到问题 . 如何命名正在执行的脚本?.bat
和.cmd
之间存在差异 . 在成功时,如果这是.cmd
文件,则第4行中的set
命令将清除(设置为0)errorlevel
变量,但如果它是.bat
文件则不会更改errorlevel
.第11,14,21行:如图所示
exeErrorlevel
变量不包含有效值 . 不,将行更改为!errorlevel!
将不会检索进程的退出代码,而是检索taskkill
的退出代码 .为了能够检索进程的退出代码/错误级别,我们需要等待它结束 . 如果你需要启动进程,如果它继续运行kill它,并且在两种情况下检索退出代码,直接调用可执行文件或使用
start "" /wait programName
,并行运行查杀程序(例如start /b "" monitor.bat programName
或类似之前启动程序) . 主进程将等待并检索退出代码 . 监视进程处理查杀 .