293

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

如果程序已经在运行,我不需要启动另一个实例。(我无法更改应用程序以使其仅成为单个实例。)

该应用程序也可以作为任何用户运行。

4

19 回答 19

360

受使用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命令的手册页。

于 2009-08-25T17:40:07.250 回答
62

以下是我的解决方法:

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

如果记事本尚未运行,则上面将打开它。

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

于 2008-10-02T13:49:32.260 回答
54

我喜欢 Chaosmaster 的解决方案!但我寻找了一个不启动另一个外部程序(如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 部分),所以它有点混乱,因为它无论如何都必须退出循环。(抱歉,我在这里不处理 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
于 2014-08-21T10:18:03.087 回答
29

npocmaka 使用 QPROCESS 而不是 TASKLIST 的建议很棒,但是它的答案是如此庞大和复杂,以至于我觉得有义务发布一个相当简化的版本,我想这将解决大多数非高级用户的问题:

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

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

于 2017-05-11T17:57:43.177 回答
22
TASKLIST | FINDSTR ProgramName || START "" "Path\ProgramName.exe"
于 2017-01-16T19:59:20.900 回答
20

在 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)

于 2011-01-24T14:23:19.847 回答
9

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!

无论如何,我希望这会有所帮助。我知道有时如果您像我一样是新手,有时阅读批处理/命令行可能会让人感到困惑。

于 2014-09-24T18:35:16.530 回答
8

我使用安装在 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
于 2008-12-02T18:29:57.037 回答
6

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

我希望这对其他人有帮助。

于 2011-08-10T08:04:34.163 回答
6

我喜欢WMICTASKLIST工具,但它们在 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

两种使用方式的区别在于QPROCESSQPROCESS *将列出所有进程,而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();
于 2014-07-30T16:19:47.700 回答
2

我不知道如何使用内置 CMD 执行此操作,但如果您有 grep,您可以尝试以下操作:

tasklist /FI "IMAGENAME eq myApp.exe" | grep myApp.exe
if ERRORLEVEL 1 echo "myApp is not running"
于 2008-10-02T13:50:16.360 回答
2

只是提一下,如果您的任务名称真的很长,那么它不会完整地出现在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
)
于 2018-05-11T19:38:18.740 回答
1

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

笔记:

  • “.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

于 2020-04-24T18:15:38.247 回答
1

如果您有多个同名的 .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
于 2021-05-12T08:39:13.683 回答
0

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

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

于 2013-09-18T13:44:48.323 回答
0

我假设这里有窗户。因此,您需要使用 WMI 来获取该信息。查看 The Scripting Guy 的档案以获取有关如何从脚本中使用 WMI 的大量示例。

于 2008-10-02T13:37:29.917 回答
0

我使用了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
于 2010-06-23T15:57:31.430 回答
-1

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

tasklist | grep program
于 2017-03-22T09:13:17.927 回答
-2

您应该检查父进程名称,请参阅有关基于.NET 的解决方案的代码项目文章** 。

一种非程序化的检查方式:

  1. 启动 Cmd.exe
  2. 启动应用程序(例如,c:\windows\notepad.exe
  3. 在Process Explorer中检查 Notepad.exe 进程的属性
  4. 检查父进程(显示 cmd.exe)

可以通过获取父进程名称来检查相同的内容。

于 2008-10-02T13:36:45.457 回答