如何检查应用程序是否从批处理(以及 cmd)文件运行?
如果程序已经在运行,我不需要启动另一个实例。(我无法更改应用程序以使其仅成为单个实例。)
该应用程序也可以作为任何用户运行。
如何检查应用程序是否从批处理(以及 cmd)文件运行?
如果程序已经在运行,我不需要启动另一个实例。(我无法更改应用程序以使其仅成为单个实例。)
该应用程序也可以作为任何用户运行。
受使用grep启发,我提出的另一种不需要保存文件的可能性是:
tasklist /fi "ImageName eq MyApp.exe" /fo csv 2>NUL | find /I "myapp.exe">NUL
if "%ERRORLEVEL%"=="0" echo Program is running
/fi ""
定义要查找的应用程序过滤器,在我们的例子中是 *.exe 名称/fo csv
定义输出格式, csv 是必需的,因为默认情况下,如果可执行文件的名称太长,可能会被截断,因此以后不会匹配find
。find /I
表示不区分大小写的匹配,可以省略有关整个语法,请参见tasklist命令的手册页。
以下是我的解决方法:
tasklist /FI "IMAGENAME eq notepad.exe" /FO CSV > search.log
FOR /F %%A IN (search.log) DO IF %%~zA EQU 0 GOTO end
start notepad.exe
:end
del search.log
如果记事本尚未运行,则上面将打开它。
编辑:请注意,这不会找到隐藏在任务列表中的应用程序。这将包括以不同用户身份运行的任何计划任务,因为这些任务会自动隐藏。
我喜欢 Chaosmaster 的解决方案!但我寻找了一个不启动另一个外部程序(如find.exe或findstr.exe)的解决方案。所以我从 Matt Lacey 的解决方案中添加了这个想法,它创建了一个也可以避免的临时文件。最后我可以找到一个相当简单的解决方案,所以我分享它......
SETLOCAL EnableExtensions
set EXE=MyProg.exe
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF NOT %%x == %EXE% (
echo %EXE% is Not Running
)
这对我很有效......
以上为编辑。原始代码中显然有一个 GOTO,评论中的某些人认为这很不礼貌。
如果您担心程序名称中可能有空格,那么您需要稍微复杂化代码:
SETLOCAL EnableExtensions
set EXE=My Prog.exe
FOR /F %%x IN ("%EXE%") do set EXE_=%%x
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF NOT %%x == %EXE_% (
echo %EXE% is Not Running
)
无论其他正在运行的进程名称中是否包含空格,原始代码都可以正常工作。唯一关心的是我们所针对的进程是否有空间。
请记住,如果您添加一个 ELSE 子句,那么它将为已经运行的应用程序的每个实例执行一次。无法保证在您运行此脚本时只有一个实例在运行。
如果您仍然想要一个,则指示一个 GOTO 或一个标志变量。
理想情况下,目标应用程序应该已经互斥自身以防止多个实例,但这是另一个 SO 问题的主题,不一定适用于该问题的主题。
我同意“ELSE”的评论。GOTO-less 解决方案的问题是,可能会多次运行条件部分(和 ELSE 部分),所以它有点混乱,因为它无论如何都必须退出循环。(抱歉,我在这里不处理 SPACE 问题,因为它似乎非常罕见,并且显示了解决方案)
SETLOCAL EnableExtensions
SET EXE=MyProg.exe
REM for testing
REM SET EXE=svchost.exe
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF NOT %%x == %EXE% (
ECHO %EXE% is Not Running
REM This GOTO may be not necessary
GOTO notRunning
) ELSE (
ECHO %EXE is running
GOTO Running
)
...
:Running
REM If Running label not exists, it will loop over all found tasks
npocmaka 使用 QPROCESS 而不是 TASKLIST 的建议很棒,但是它的答案是如此庞大和复杂,以至于我觉得有义务发布一个相当简化的版本,我想这将解决大多数非高级用户的问题:
QPROCESS "myprocess.exe">NUL
IF %ERRORLEVEL% EQU 0 ECHO "Process running"
上面的代码在 Windows 7 中进行了测试,用户具有管理员权限。
TASKLIST | FINDSTR ProgramName || START "" "Path\ProgramName.exe"
在 Windows 下,您可以使用 Windows Management Instrumentation (WMI) 来确保不会启动具有指定命令行的应用程序,例如:
wmic process where (name="nmake.exe") get commandline | findstr /i /c:"/f load.mak" /c:"/f build.mak" > NUL && (echo THE BUILD HAS BEEN STARTED ALREADY! > %ALREADY_STARTED% & exit /b 1)
TrueY 的答案似乎是最优雅的解决方案,但是,我不得不做一些乱七八糟的事情,因为我不明白到底发生了什么。让我把事情弄清楚,希望能为下一个人节省一些时间。
TrueY 修改后的答案:
::Change the name of notepad.exe to the process .exe that you're trying to track
::Process names are CASE SENSITIVE, so notepad.exe works but Notepad.exe does NOT
::Do not change IMAGENAME
::You can Copy and Paste this into an empty batch file and change the name of
::notepad.exe to the process you'd like to track
::Also, some large programs take a while to no longer show as not running, so
::give this batch a few seconds timer to avoid a false result!!
@echo off
SETLOCAL EnableExtensions
set EXE=notepad.exe
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF %%x == %EXE% goto ProcessFound
goto ProcessNotFound
:ProcessFound
echo %EXE% is running
goto END
:ProcessNotFound
echo %EXE% is not running
goto END
:END
echo Finished!
无论如何,我希望这会有所帮助。我知道有时如果您像我一样是新手,有时阅读批处理/命令行可能会让人感到困惑。
我使用安装在 Program Files\PV 中的http://www.teamcti.com/pview/prcview.htm的PV.exe和一个像这样的批处理文件:
@echo off
PATH=%PATH%;%PROGRAMFILES%\PV;%PROGRAMFILES%\YourProgram
PV.EXE YourProgram.exe >nul
if ERRORLEVEL 1 goto Process_NotFound
:Process_Found
echo YourProgram is running
goto END
:Process_NotFound
echo YourProgram is not running
YourProgram.exe
goto END
:END
Matt Lacey 提供的答案适用于 Windows XP。但是,在 Windows Server 2003 中,该行
tasklist /FI "IMAGENAME eq notepad.exe" /FO CSV > search.log
返回
信息:没有运行符合指定条件的任务。
然后在进程运行时读取它。
我没有大量的批处理脚本经验,所以我的解决方案是在search.log
文件中搜索进程名称并将结果泵入另一个文件并搜索任何输出。
tasklist /FI "IMAGENAME eq notepad.exe" /FO CSV > search.log
FINDSTR notepad.exe search.log > found.log
FOR /F %%A IN (found.log) DO IF %%~zA EQU 0 GOTO end
start notepad.exe
:end
del search.log
del found.log
我希望这对其他人有帮助。
我喜欢WMIC
和TASKLIST
工具,但它们在 Windows 的家庭/基本版中不可用。另一种方法是使用QPROCESS
几乎每台 Windows 机器上可用的命令(对于那些有终端服务的机器 - 我认为只有在没有 SP2 的情况下才能赢得 XP,所以几乎每个窗户机):
@echo off
:check_process
setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
set process_to_check=%~1
:: QPROCESS can display only the first 12 symbols of the running process
:: If other tool is used the line bellow could be deleted
set process_to_check=%process_to_check:~0,12%
QPROCESS * | find /i "%process_to_check%" >nul 2>&1 && (
echo process %process_to_check% is running
) || (
echo process %process_to_check% is not running
)
endlocal
QPROCESS
命令没有那么强大,并且仅限于显示进程名称的 12 个符号,但如果不可用TASKLIST
,则应予以考虑。TASKLIST
更简单的用法,如果进程作为参数,则使用名称(在.exe
传递可执行名称的情况下,后缀是强制性的):
@echo off
:check_process
setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
:: .exe suffix is mandatory
set "process_to_check=%~1"
QPROCESS "%process_to_check%" >nul 2>&1 && (
echo process %process_to_check% is running
) || (
echo process %process_to_check% is not running
)
endlocal
两种使用方式的区别在于QPROCESS
,QPROCESS *
将列出所有进程,而QPROCESS some.exe
仅过滤当前用户的进程。
WMI
通过 Windows 脚本主机 exe 而不是使用对象WMIC
也是一个选项。它也应该在每台 Windows 机器上运行(不包括关闭 WSH 的机器,但这是一种罕见的情况)。这里是通过 WMI 列出所有进程的 bat 文件类,并且可以QPROCESS
在上面的脚本中使用(它是 jscript/bat 混合体,应另存为.bat
):
@if (@X)==(@Y) @end /* JSCRIPT COMMENT **
@echo off
cscript //E:JScript //nologo "%~f0"
exit /b
************** end of JSCRIPT COMMENT **/
var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
var processes = new Enumerator(colProcess);
for (;!processes.atEnd();processes.moveNext()) {
var process=processes.item();
WScript.Echo( process.processID + " " + process.Name );
}
以及检查进程是否正在运行的修改:
@if (@X)==(@Y) @end /* JSCRIPT COMMENT **
@echo off
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
set process_to_check=%~1
cscript //E:JScript //nologo "%~f0" | find /i "%process_to_check%" >nul 2>&1 && (
echo process %process_to_check% is running
) || (
echo process %process_to_check% is not running
)
exit /b
************** end of JSCRIPT COMMENT **/
var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
var processes = new Enumerator(colProcess);
for (;!processes.atEnd();processes.moveNext()) {
var process=processes.item();
WScript.Echo( process.processID + " " + process.Name );
}
这两个选项可用于没有TASKLIST
.
终极技术是使用MSHTA
. 这将在 XP 及更高版本的每台 Windows 机器上运行,并且不依赖于 Windows 脚本主机设置。的调用MSHTA
可能会降低一点性能(再次应保存为 bat):
@if (@X)==(@Y) @end /* JSCRIPT COMMENT **
@echo off
setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
set process_to_check=%~1
mshta "about:<script language='javascript' src='file://%~dpnxf0'></script>" | find /i "%process_to_check%" >nul 2>&1 && (
echo process %process_to_check% is running
) || (
echo process %process_to_check% is not running
)
endlocal
exit /b
************** end of JSCRIPT COMMENT **/
var fso= new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1);
var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
var processes = new Enumerator(colProcess);
for (;!processes.atEnd();processes.moveNext()) {
var process=processes.item();
fso.Write( process.processID + " " + process.Name + "\n");
}
close();
我不知道如何使用内置 CMD 执行此操作,但如果您有 grep,您可以尝试以下操作:
tasklist /FI "IMAGENAME eq myApp.exe" | grep myApp.exe
if ERRORLEVEL 1 echo "myApp is not running"
只是提一下,如果您的任务名称真的很长,那么它不会完整地出现在tasklist
结果中,因此检查相反的名称可能更安全(除了本地化)。
这个答案的变化:
:: in case your task name is really long, check for the 'opposite' and find the message when it's not there
tasklist /fi "imagename eq yourreallylongtasknamethatwontfitinthelist.exe" 2>NUL | find /I /N "no tasks are running">NUL
if "%errorlevel%"=="0" (
echo Task Found
) else (
echo Not Found Task
)
我需要一个重试的解决方案。此代码将一直运行,直到找到该进程,然后将其终止。如果你愿意,你可以设置一个超时或任何东西。
笔记:
:: Set programm you want to kill
:: Fileextension is mandatory
SET KillProg=explorer.exe
:: Set waiting time between 2 requests in seconds
SET /A "_wait=3"
:ProcessNotFound
tasklist /NH /FI "IMAGENAME eq %KillProg%" | FIND /I "%KillProg%"
IF "%ERRORLEVEL%"=="0" (
TASKKILL.EXE /F /T /IM %KillProg%
) ELSE (
timeout /t %_wait%
GOTO :ProcessNotFound
)
taskkill.bat
:
:: Get program name from argumentlist
IF NOT "%~1"=="" (
SET "KillProg=%~1"
) ELSE (
ECHO Usage: "%~nx0" ProgramToKill.exe & EXIT /B
)
:: Set waiting time between 2 requests in seconds
SET /A "_wait=3"
:ProcessNotFound
tasklist /NH /FI "IMAGENAME eq %KillProg%" | FIND /I "%KillProg%"
IF "%ERRORLEVEL%"=="0" (
TASKKILL.EXE /F /T /IM %KillProg%
) ELSE (
timeout /t %_wait%
GOTO :ProcessNotFound
)
运行.\taskkill.bat ProgramToKill.exe
如果您有多个同名的 .exe 文件并且您只想检查其中一个(例如,您关心 C:\MyProject\bin\release\MyApplication.exe 而不是 C:\MyProject\bin\debug \MyApplication.exe) 那么您可以使用以下命令:
@echo off
set "workdir=C:\MyProject\bin\release"
set "workdir=%workdir:\=\\%"
setlocal enableDelayedExpansion
for /f "usebackq tokens=* delims=" %%a in (`
wmic process where 'CommandLine like "%%!workdir!%%" and not CommandLine like "%%RuntimeBroker%%"' get CommandLine^,ProcessId /format:value
`) do (
for /f "tokens=* delims=" %%G in ("%%a") do (
if "%%G" neq "" (
rem echo %%G
set "%%G"
rem echo !ProcessId!
goto :TheApplicationIsRunning
)
)
)
echo The application is not running
exit /B
:TheApplicationIsRunning
echo The application is running
exit /B
基于vtrz 的回答和Samuel Renkert 对另一个主题的回答,我提出了以下脚本,该脚本仅在%EXEC_CMD%
尚未运行时运行:
@echo off
set EXEC_CMD="rsync.exe"
wmic process where (name=%EXEC_CMD%) get commandline | findstr /i %EXEC_CMD%> NUL
if errorlevel 1 (
%EXEC_CMD% ...
) else (
@echo not starting %EXEC_CMD%: already running.
)
如前所述,这需要管理权限。
我假设这里有窗户。因此,您需要使用 WMI 来获取该信息。查看 The Scripting Guy 的档案以获取有关如何从脚本中使用 WMI 的大量示例。
我使用了Matt (2008-10-02) 提供的脚本。我唯一遇到的问题是它不会删除search.log
文件。我希望是因为我不得不cd
到另一个地方开始我的程序。我cd
会回到 BAT 文件所在的search.log
位置,但它仍然不会删除。所以我通过search.log
首先删除文件而不是最后一个来解决这个问题。
del search.log
tasklist /FI "IMAGENAME eq myprog.exe" /FO CSV > search.log
FOR /F %%A IN (search.log) DO IF %%-zA EQU 0 GOTO end
cd "C:\Program Files\MyLoc\bin"
myprog.exe myuser mypwd
:end
我通常在 cmd 提示符下执行以下命令来检查我的 program.exe 是否正在运行:
tasklist | grep program
您应该检查父进程名称,请参阅有关基于.NET 的解决方案的代码项目文章** 。
一种非程序化的检查方式:
c:\windows\notepad.exe
)可以通过获取父进程名称来检查相同的内容。