简体   繁体   English

ERRORLEVEL vs %ERRORLEVEL% vs 感叹号 ERRORLEVEL 感叹号

[英]ERRORLEVEL vs %ERRORLEVEL% vs exclamation mark ERRORLEVEL exclamation mark

I think i have a basic understanding of ERRORLEVEL vs %ERRORLEVEL% but !ERRORLEVEL!我想我对 ERRORLEVEL 与 %ERRORLEVEL% 有基本的了解,但是 !ERRORLEVEL! confuses me.让我困惑。

I'm making a script that calls an executable, then tasklist to see if its running, then taskkill to kill it if it is and then trying to output the errorlevels and repeating for other exe's and i'm realising i really don't understand errorlevels in batch.我正在制作一个调用可执行文件的脚本,然后是 tasklist 以查看它是否正在运行,然后 taskkill 将其杀死(如果是),然后尝试输出错误级别并为其他 exe 重复,我意识到我真的不明白批量错误级别。

I set a variable equal to !errorlevel!我设置了一个等于 !errorlevel! 的变量! then used that variable without quotation marks in an echo, and the variable changed from one uint16 to another uint16 when there was an error after the set, like its a reference to the real one instead of a copy.然后在回显中使用不带引号的变量,当设置后出现错误时,变量从一个 uint16 更改为另一个 uint16,就像它是对真实变量而不是副本的引用。 I want copy.我要副本。 Can someone explain the difference between these guys?有人可以解释这些人之间的区别吗?


Update: Here is the snippet I'm working on.更新:这是我正在处理的片段。

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%


)

I need to make sure exeErrorlevel has a copy of the errorlevel at a certain point in time - I only want to capture errors from the exe, not from the success/failure of tasklist/find/taskill.我需要确保 exeErrorlevel 在某个时间点有错误级别的副本 - 我只想从 exe 中捕获错误,而不是从 tasklist/find/taskill 的成功/失败中捕获错误。 I'm concerned that exeerrorlevel, because of the delayed expansion, is accessing the delayed errorlevel upon execution.我担心 exeerrorlevel 由于延迟扩展而在执行时访问延迟的错误级别。 perhaps that should be set exeErrorlevel=%errorlevel% instead.也许应该设置 exeErrorlevel=%errorlevel% 代替。 In the line where i echo older and newer variables usually return different integers?在我回显较旧和较新变量的行中通常返回不同的整数? In all my test runs %errorlevel% seems to typically return 0 whereas !errorlevel!在我所有的测试运行中 %errorlevel% 似乎通常返回 0 而 !errorlevel! is consistently non zero for executables with bad exit codes.对于具有错误退出代码的可执行文件,始终为非零。

The errorlevel错误级别

errorlevel is the name of a dynamic variable (it is not placed in the environment block but hold in memory) that stores the exit code of the previous executed process/command (if it sets that value, read here , here , here and here ). errorlevel是一个动态变量的名称(它不放置在环境块中,而是保存在内存中),它存储先前执行的进程/命令的退出代码(如果设置了该值,请阅读此处此处此处此处) .

The if command allows the usage of the if errorlevel n syntax to check if the value of the errorlevel variable is greater than or equal to n , without involving the batch parser into retrieving the value of the variable. if命令允许使用if errorlevel n语法来检查errorlevel变量的值是否大于或等于n ,而无需批处理解析器检索变量的值。

But, if we put the batch parser to work with variable values, %errorlevel% is just a reference to the value stored in the variable, a read operation.但是,如果我们让批处理解析器处理变量值, %errorlevel%只是对存储在变量中的值的引用,一个读取操作。 Just the same as !errorlevel!!errorlevel!相同!errorlevel! . . The main difference between the two is when the value is retrieved depending on the rules on variable expansion.两者之间的主要区别在于何时根据变量扩展规则检索值。

There is a great difference in using the if errorlevel or retrieving the value in the variable:使用if errorlevel或检索变量中的值有很大的不同:

  • The variable read operation will check if the environment block contains a variable with the indicated name.变量读取操作将检查环境块是否包含具有指定名称的变量。
  • The if constuct will not make this test. if构造不会进行此测试。

If you do something like set errorlevel=10 , the dynamic errorlevel value will not be retrieved with %errorlevel% or !errorlevel!如果您执行类似set errorlevel=10 ,则不会使用%errorlevel%!errorlevel!检索动态errorlevel!errorlevel! as the value set in the environment will hide the dynamic value.因为在环境中设置的值将隐藏动态值。 But as if errorlevel does not read the environment block but directly reads the internal variable that holds the value, it will work without problems.但是if errorlevel不读取环境块而是直接读取保存值的内部变量,它会毫无问题地工作。

The variables变量

The batch syntax does not include the option of having more than one variable pointing to the same value in memory in a way that if one of the variables changes its value, the other will reflect the change.批处理语法不包括让多个变量指向内存中相同值的选项,如果其中一个变量更改其值,另一个将反映该更改。

This behaviour can be simulated by proper use of the different phases in variable expansion, properly setting a variable to the name of another and forcing the batch parser to do two passes over the command so first variable is resolved to the name of the second and that to the real value.可以通过正确使用变量扩展中的不同阶段来模拟这种行为,将变量正确设置为另一个变量的名称并强制批处理解析器对命令执行两次传递,以便将第一个变量解析为第二个变量的名称,然后到真正的价值。

Your problem你的问题

Simplified (non even working) code just for analysis仅用于分析的简化(非工作)代码

 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      )
  • line 1: the code in the do clause, all the code, is parsed.第 1 行:解析do子句中的所有代码。 Any %var% variable read operation is removed from the code, replaced with the value inside the variable before starting the execution.任何%var%变量读取操作都将从代码中删除,并在开始执行之前替换为变量内的值。 This means that if the variable changes its value you will not be able to retrieve the changed value as the read operation does not exist, only the initial value in the variable.这意味着如果变量更改其值,您将无法检索更改的值,因为读取操作不存在,只有变量中的初始值。

  • line 3: the executable is launched, in a separate process, without waiting for the process to end.第 3 行:可执行文件在单独的进程中启动,无需等待进程结束。 Is it important?那很重要么? See next line见下一行

  • line 4: the current (delayed expansion used) value of the errorlevel variable is retrieved and stored in exeErrorlevel variable.第 4 行:检索errorlevel变量的当前(使用延迟扩展)值并将其存储在exeErrorlevel变量中。 BUT the value stored is NOT the errorlevel returned by the executable (separate process, not waiting for it to end, how will we know what the exit code = errorlevel is?), but the exit code of the start command.但是存储的值不是可执行文件返回的错误errorlevel (单独的进程,不等待它结束,我们怎么知道exit code = errorlevel是什么?),而是start命令的退出代码。

  • line 6: as the %errorlevel% read operation was removed, this line will echo the value that was stored in the errorlevel variable before the do clause started to execute.第 6 行:由于%errorlevel%读取操作被删除,该行将回显在do子句开始执行之前存储在errorlevel变量中的值。

  • line 7: the current value of the errorlevel variable is retrieved.第 7 行:检索errorlevel变量的当前值。 And here, we can have a problem.在这里,我们可能会遇到问题。 How the script being executed is named?正在执行的脚本是如何命名的? There is a difference between .bat and .cmd . .bat.cmd之间存在差异。 On sucess the set command in line 4 will clear (set to 0) the errorlevel variable if this is a .cmd file, but will not change the errorlevel if it is a .bat file.成功后,如果这是一个.cmd文件,第 4 行中的set命令将清除(设置为 0) errorlevel变量,但如果它是一个.bat文件,则不会更改错误errorlevel

  • lines 11, 14, 21: as seen the exeErrorlevel variable does not contain a valid value.exeErrorlevel行:如所见, exeErrorlevel变量不包含有效值。 And no, changing the lines to !errorlevel!不,将行更改为!errorlevel! will not retrieve the exit code of the process, but the exit code of the taskkill .不会检索进程的退出代码,而是获取taskkill的退出代码。

To be able to retrieve the exit code / errorlevel of a process we need to wait for it to end.为了能够检索进程的退出代码/错误级别,我们需要等待它结束。 If you need to start the process, if it keeps running kill it, and in both cases retrieve the exit code, directly call the executable or use start "" /wait programName , AND run the killing process in parallel (ex. start /b "" monitor.bat programName or something similar before starting the program).如果您需要启动进程,如果它一直运行杀死它,并且在两种情况下都检索退出代码,则直接调用可执行文件或使用start "" /wait programName ,并并行运行终止进程(例如start /b "" monitor.bat programName在启动程序之前start /b "" monitor.bat programName或类似的东西)。 The main process will wait and retrieve the exit code.主进程将等待并检索退出代码。 The monitor process handles the killing.监视器进程处理查杀。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM