测试 TASKKILL 错误级别的语法

Posted

技术标签:

【中文标题】测试 TASKKILL 错误级别的语法【英文标题】:syntax for testing TASKKILL's errorlevel 【发布时间】:2018-12-20 01:36:45 【问题描述】:

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

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

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

如果结果是“信息:没有任务按照指定的条件运行”。我需要批处理文件来再次尝试TASKKILL

如果结果是“成功:发送终止信号到...。”我需要关闭批处理文件。

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

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

【参考方案2】:

打开命令提示符窗口并运行if /?。输出帮助解释了如何使用命令 IF 更正检查错误级别,使用语法 if errorlevel X ... 从 MS-DOS 开始工作,也在命令块内工作。

if %errorlevel% == 1 goto ShiftFocus 在以( 开头并以匹配) 结尾的命令块中不起作用,因为Windows 命令处理器会按值替换整个命令块中所有出现的%variable%在完全执行命令块之前引用的环境变量。这可以在命令提示符窗口中运行没有@echo off 的批处理文件时看到。

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

也可以使用if errorlevel 1 if not errorlevel 2 goto ShiftFocus,表示退出代码大于或等于1不大于或等于2,即喜欢@ C、C++、C#、javascript 等中的 987654340@,如果需要对退出代码 1 进行显式测试,但不包括退出代码 128

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

然而,真正的问题是在 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\User\1173051_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\User\1173051_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 的情况下使用,因为它使得在命令提示符窗口中运行批处理文件而不是双击它时测试批处理文件非常困难。详情请见debugging a batch file。

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

但由于aschipfl 解释的原因,此批处理文件不起作用:TASKKILL 在使用过滤器选项/FI 时不会以CatCat 所写的值128 退出,并且没有正在运行与过滤器匹配的进程。

aschipfl 发布了一个解决TASKKILL 怪癖的独立于语言的解决方案。

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

:Launch
start "CloseMe" "C:\Program Files\Internet Explorer\iexplore.exe" "file://C:\ProgramData\Schneider Electric\Citect SCADA 2016\User\1173051_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\User\1173051_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 的情况下,没有找到窗口标题为CloseMe - Internet Explorer 的Internet Explorer 实例,导致1 秒后跳转到ShiftFocus 并再次运行VBScript 和TASKKILL

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

【讨论】:

【参考方案3】:
taskkill /f /im wscript.exe
echo %errorlevel%
pause

%errorlevel%

0 表示成功

1 表示拒绝访问

128 无所事事

【讨论】:

当我将 TASKKILL 开关更改为我需要的值时,%errorlevel% 始终为 0【参考方案4】:

您可以保留过滤器,当您通过管道将输出传递到 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

【讨论】:

以上是关于测试 TASKKILL 错误级别的语法的主要内容,如果未能解决你的问题,请参考以下文章

intellisense 无法找出 Visual Studio 和 C# 中的“内部”可访问性级别语法错误

进程命令(taskkill)

在taskkill windowtitle中的通配符

java.sql.SQLException: ORA-00604: 递归 SQL 级别 1 出现错误 ORA-01003: 语句未进行语法分析

错误:消息102,级别15,状态1,过程InsertCustomers,第30行'THROW'附近的语法不正确

PHP错误级别