如何检查进程是否通过批处理脚本运行

如何检查应用程序是否从批处理(好cmd)文件运行?

如果程序已经在运行,我不需要启动另一个实例。(我不能改变应用程序,使它只有单一实例。)

此外,应用程序可以作为任何用户运行。

723703 次浏览

你应该检查父进程名,参见代码项目关于.NET解决方案**. conf的文章。

一种非编程的检查方法:

  1. 发射用于cmd . exe
  2. 启动一个应用程序(例如,c:\windows\notepad.exe)
  3. 检查Process 探险家中Notepad.exe进程的属性
  4. 检查父进程(显示cmd.exe)

同样可以通过获取父进程名进行检查。

我假设这里是窗户。因此,您需要使用WMI来获取该信息。查看脚本Guy的档案,有很多关于如何从脚本中使用WMI的例子。

以下是我的解决方法:

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

如果记事本尚未运行,上面的语句将打开记事本

编辑:注意这不会发现隐藏在任务列表中的应用程序。这将包括以不同用户运行的任何计划任务,因为这些任务将自动隐藏。

我不知道如何用内置CMD这样做,但如果你有grep,你可以尝试以下:

tasklist /FI "IMAGENAME eq myApp.exe" | grep myApp.exe
if ERRORLEVEL 1 echo "myApp is not running"

我使用PV.exe从http://www.teamcti.com/pview/prcview.htm安装在程序文件\PV与这样的批处理文件:

@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

我提出的另一种不需要保存文件的可能性,受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命令的手册页。

我使用Matt提供的脚本(2008-10-02)。我唯一遇到的麻烦是它不会删除search.log文件。我希望,因为我必须cd到另一个位置来启动我的程序。我__abc1d回到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

在Windows下,您可以使用Windows管理规范(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)

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

我希望这能帮助到其他人。

基于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.
)

如前所述,这需要管理特权。

我喜欢WMICTASKLIST工具,但它们在windows的家庭/基本版本中不可用。另一种方法是在几乎所有windows机器上使用QPROCESS命令(对于那些有终端服务的机器-我认为只能赢得XP而没有SP2,所以几乎所有windows机器):

@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 < / >强命令没有TASKLIST那么强大,并且只能显示12个进程名符号,但是如果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将仅为当前用户过滤进程。

通过windows脚本主机exe使用WMI对象而不是WMIC也是一个选项。它还应该在每台windows机器上运行(不包括关闭WSH的机器,但这种情况很少见)。下面是一个bat文件,它列出了通过WMI类的所有进程,可以用来代替上面脚本中的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。这将运行在每一台windows机器从XP和以上,不依赖于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();

我喜欢《混沌大师》的解决方案!但我寻找了一个解决方案,不启动另一个外部程序(如find.exefindstr.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部分),所以它有点混乱,因为它必须退出循环。(对不起,我在这里不处理空间问题,因为它似乎相当罕见,并显示了一个解决方案)

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

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!

不管怎样,我希望这对你们有帮助。我知道,如果你像我一样是新手,阅读批处理/命令行有时会有点困惑。

TASKLIST | FINDSTR ProgramName || START "" "Path\ProgramName.exe"

我通常在cmd提示符下执行以下命令来检查我的program.exe是否正在运行:

tasklist | grep program

npocmaka使用QPROCESS代替TASKLIST的建议很好,但是,它的答案太大太复杂了,我觉得有义务发布一个相当简化的版本,我想,这将解决大多数非高级用户的问题:

QPROCESS "myprocess.exe">NUL
IF %ERRORLEVEL% EQU 0 ECHO "Process running"

上面的代码是在Windows 7中测试的,用户具有管理员权限。

只是提一下,如果你的任务名称真的很长,那么它不会完整地出现在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
)

我需要一个重试的解决方案。这段代码将一直运行,直到找到进程,然后将其终止。你可以设置一个超时或任何你喜欢的东西。

注:

  • “。exe”是必选项
  • 你可以让一个文件运行参数,版本如下
    :: 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