测试 TASKKILL 错误级别的语法

syntax for testing TASKKILL's errorlevel

在下面显示的批处理文件的上下文中测试 TASKKILLerrorlevel 的正确语法是什么?

:Launch
   start "CloseMe" "C:\Program Files\internet explorer\iexplore.exe" "file://C:\ProgramData\Schneider Electric\Citect SCADA 2016\User73051_SM_STP\Files\Stony Mountain Institute Lift Station.html"
   TIMEOUT 1 & 
:ShiftFocus
   wscript "C:\ProgramData\Schneider Electric\Citect SCADA 2016\User73051_SM_STP\Files\SendAltTab.vbs"
   TASKKILL /IM iexplore.exe /FI "WINDOWTITLE eq CloseMe - Internet Explorer"
   if %errorlevel% == 1 GOTO ShiftFocus
:End
exit

我正在尝试将我的批处理文件 运行 TASKKILL 然后测试结果。

如果结果是 "INFO: No tasks running with the specified criteria." 我需要批处理文件再试一次 TASKKILL

如果结果是"SUCCESS: Sent termination signal to ... ."我需要关闭批处理文件。

为了实现这一点,我使用了我在 here and here 中学到的 if 语句、标签和 goto。

我怀疑我错误地使用了错误级别,因为无论 TASKKILL 做什么,从我的批处理文件的角度来看,它的错误级别都是 0。类似帖子的一些答案使用 %errorlevel% 和其他人正在使用 errorlevel。无论我在我的批处理文件中使用哪个,它都会看到 0 的错误级别,而不管 TASKKILL.

的实际结果如何
taskkill /f /im wscript.exe
echo %errorlevel%
pause

%errorlevel%

0 for success

1 for Access Denied

128 for nothing to kill

打开命令提示符 window 和 运行 if /?。输出帮助解释了如何使用自 MS-DOS 以来工作的语法 if errorlevel X ... 以及在命令块中工作的语法 IF 来更正检查错误级别。

if %errorlevel% == 1 goto ShiftFocus 在以 ( 开始并以匹配 ) 结束的命令块中不起作用,因为 Windows 命令处理器替换了批处理文件编写的初学者在执行命令块之前,根据引用环境变量的值,整个命令块中出现的所有 %variable%。这可以在命令提示符 window.

中 运行 在没有 @echo off 的批处理文件中看到

另请参阅 single line with multiple commands using Windows batch file 解释如何使用 if errorlevel X ... 或使用运算符 &&||.[=51= 评估命令或应用程序的退出代码]

也可以使用 if errorlevel 1 if not errorlevel 2 goto ShiftFocus,这意味着退出代码 大于或等于 1 不大于或等于 2,即像 C、C++、C# 中的 if ((errorlevel >= 1) && (errorlevel < 2))、JavaScript 等,如果需要对退出代码 1 进行显式测试排除退出代码 128.

也可以启用 delayed expansion 并按照 运行ning set /? 上命令 SET 输出的帮助说明使用它在命令提示符 window 和 if !errorlevel! == 1 goto ShiftFocus 中。但是,延迟扩展的使用可能会导致其他问题,并且由于对每个命令行进行双重解析而使批处理文件处理速度变慢,我真的不建议将其仅用于评估命令或应用程序的退出代码。

然而,真正的问题是在没有 运行 的 Internet Explorer 上,批处理文件应该跳转到标签 ShiftFocus 根据有问题的解释,这可以通过使用 if errorlevel 128 goto ShiftFocus.

所以整个批处理文件可以是:

:Launch
start "CloseMe" "C:\Program Files\Internet Explorer\iexplore.exe" "file://C:\ProgramData\Schneider Electric\Citect SCADA 2016\User73051_SM_STP\Files\Stony Mountain Institute Lift Station.html"
%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK >nul

:ShiftFocus
%SystemRoot%\System32\wscript.exe "C:\ProgramData\Schneider Electric\Citect SCADA 2016\User73051_SM_STP\Files\SendAltTab.vbs"
%SystemRoot%\System32\taskkill.exe /IM iexplore.exe /FI "WINDOWTITLE eq CloseMe - Internet Explorer"
if errorlevel 128 %SystemRoot%\System32\timeout.exe /T 1 /NOBREAK >nul & goto ShiftFocus

exit /B

最好使用具有完整路径和文件扩展名的控制台应用程序(外部命令),使批处理文件独立于环境变量 PATHPATHEXT

并且命令 exit 不应该在没有选项 /B 的情况下使用,因为它使得在命令提示符 window 中 运行 测试批处理文件变得非常困难而不是双击它。详情见 debugging a batch file

在跳转到 ShiftFocus 和 运行 脚本之前添加了额外的一秒钟等待,因为快速 运行 脚本和 taskkill循环对我来说没有意义。

但是由于 aschipfl: TASKKILL does not exit with value 128 as written by CatCat 在使用过滤器选项 /FI 中解释的原因,此批处理文件不起作用,并且没有 运行ning 进程匹配过滤器。

aschipfl.

发布了解决 TASKKILL 这个问题的独立于语言的解决方案

依赖于语言的解决方案将使用此批处理文件:

:Launch
start "CloseMe" "C:\Program Files\Internet Explorer\iexplore.exe" "file://C:\ProgramData\Schneider Electric\Citect SCADA 2016\User73051_SM_STP\Files\Stony Mountain Institute Lift Station.html"
%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK >nul

:ShiftFocus
%SystemRoot%\System32\wscript.exe "C:\ProgramData\Schneider Electric\Citect SCADA 2016\User73051_SM_STP\Files\SendAltTab.vbs"
for /F "delims=:" %%I in ('%SystemRoot%\System32\taskkill.exe /IM iexplore.exe /FI "WINDOWTITLE eq CloseMe - Internet Explorer"') do if "%%I" == "INFO" %SystemRoot%\System32\timeout.exe /T 1 /NOBREAK >nul & goto ShiftFocus

exit /B

TASKKILL 命令行由 FOR 在后台以 cmd /C 启动的单独命令进程中执行。 TASKKILL 输出的用于处理此后台命令进程中的 STDOUT 的行被 FOR 捕获。然后使用冒号作为分隔符将捕获的行拆分为子字符串。第一个冒号之前的字符串被分配给循环变量I。此字符串在这里依赖于语言 INFOSUCCESS。在 INFO 的情况下,没有找到带有 window 标题 CloseMe - Internet Explorer 的 Internet Explorer 实例,导致在 1 秒后跳转到 ShiftFocus 并且 运行 将 VBScript 和TASKKILL 再一次。

如果批处理文件应该 运行 在装有 Windows Vista 或更高版本 Windows 的任何 Windows 机器上,则不应使用此 Windows 语言相关解决方案] 版本独立于 Windows.

的语言

taskkill 清除 ErrorLevel 当你提供了一个过滤器 /FI 导致不匹配!但是,当您仅过滤图像名称 (/IM) 或进程 ID (/PID) 时,如果未遇到任何匹配项,ErrorLevel 将设置为 128

因此,我将通过 tasklist 预过滤进程,并使用 taskkill 及其 /PID 过滤器:

:LOOP
rem // Establish a short wait time to not heavily load the processor:
> nul timeout /T 1 /NOBREAK
rem // Prefilter processes and retrieve the PID of the applicable one:
set "PID=" & for /F "tokens=1* delims=:" %%T in ('
    tasklist /FI "IMAGENAME eq iexplore.exe" /FI "WINDOWTITLE eq CloseMe - Internet Explorer" /FO LIST
') do if "%%T"=="PID" for /F %%W in ("%%U") do set "PID=%%W"
rem // Loop back in case no PID could be retrieved:
if not defined PID goto :LOOP
rem // Try to kill the task and loop back in case of failure:
taskkill /PID %PID% || goto :LOOP

当您将输出通过管道传输到 find 命令时,您可以保留过滤器,因此您评估 find 的错误级别而不是 taskkill 的错误级别:

:ShiftFocus
...
TASKKILL /IM iexplore.exe /FI "WINDOWTITLE eq CloseMe - Internet Explorer" | find "SUCCESS:" && goto :eof
goto :ShiftFocus

:ShiftFocus
...
TASKKILL /IM iexplore.exe /FI "WINDOWTITLE eq CloseMe - Internet Explorer" | find "No tasks running" && goto :ShiftFocus