ERRORLEVEL 与 %ERRORLEVEL% 与感叹号 ERRORLEVEL 感叹号

ERRORLEVEL vs %ERRORLEVEL% vs exclamation mark ERRORLEVEL exclamation mark

我想我对 ERRORLEVEL 与 %ERRORLEVEL% 有基本的了解,但是 !ERRORLEVEL!让我困惑。

我正在制作一个调用可执行文件的脚本,然后是 tasklist 以查看它是否 运行,然后 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 在某个时间点有错误级别的副本 - 我只想捕获来自 exe 的错误,而不是来自 tasklist/find/taskill 的 success/failure。我担心 exeerrorlevel 由于延迟扩展而在执行时访问延迟错误级别。也许应该改为设置 exeErrorlevel=%errorlevel% 。在我回显旧变量和新变量的行中,通常 return 不同的整数?在我所有的测试运行中,%errorlevel% 似乎通常是 return 0 而 !errorlevel!对于退出代码错误的可执行文件,始终不为零。

错误级别

errorlevel 是一个动态变量的名称(它不放在环境块中,而是保存在内存中),它存储先前执行的 process/command 的退出代码(如果它设置值,读 , , and here).

if命令允许使用if errorlevel n语法来检查errorlevel变量的值是否大于或等于n,而不涉及批解析器检索变量的值。

但是,如果我们让批解析器处理变量值,%errorlevel% 只是对存储在变量中的值的引用,即读取操作。就和!errorlevel!一样。两者之间的主要区别是 when 取值取决于 rules on variable expansion.

使用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 是什么?),而是 [= 的退出代码31=] 命令。

  • 第 6 行:由于删除了 %errorlevel% 读取操作,此行将回显 do 子句之前存储在 errorlevel 变量中的值开始执行了。

  • 第 7 行:检索 errorlevel 变量的当前值。在这里,我们可能会遇到问题。正在执行的脚本是如何命名的? .bat.cmd 是有区别的。如果这是一个 .cmd 文件,第 4 行中的 set 命令将清除(设置为 0)变量 errorlevel,但如果它是 errorlevel,则不会更改 errorlevel一个 .bat 文件。

  • 第 11、14、21 行:如所见,exeErrorlevel 变量不包含有效值。不,将行更改为 !errorlevel! 不会检索进程的退出代码,而是检索 taskkill.

  • 的退出代码

为了能够检索进程的退出代码/错误级别,我们需要等待它结束。如果你需要启动进程,如果它保持 运行ning 杀死它,并且在这两种情况下检索退出代码,直接调用可执行文件或使用 start "" /wait programName,并且 运行 杀死进程并行(例如 start /b "" monitor.bat programName 或启动程序之前的类似内容)。主进程将等待并检索退出代码。监控进程处理杀戮。