[英]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
或检索变量中的值有很大的不同:
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.