Como verificar se um processo está sendo executado por meio de um script em lote

260

Como posso verificar se um aplicativo está sendo executado a partir de um arquivo em lote (cmd)?

Preciso não iniciar outra instância se um programa já estiver sendo executado. Não consigo alterar o aplicativo para torná-lo apenas uma instância.

Além disso, o aplicativo pode estar sendo executado como qualquer usuário.

Matt Lacey
fonte
12
duplicado de uma pergunta feita cinco anos depois?
Matt Lacey
@ LưuVĩnhPhúc eles nem são relativamente próximos.
Cardinal - Restabelece Monica
@JackKirby, que disse que não está relacionado?
phuclv
3
@oopsdazie sim eu posso estar errado neste caso, mas a regra geral é a de manter a questão com a melhor coleção de respostas, e fechar o outro como uma duplicata , independentemente do tempo
phuclv

Respostas:

330

Outra possibilidade que surgiu, inspirada no uso do grep , é:

tasklist /FI "IMAGENAME eq myapp.exe" 2>NUL | find /I /N "myapp.exe">NUL
if "%ERRORLEVEL%"=="0" echo Program is running

Como não é necessário salvar um arquivo extra, prefiro esse método.

pkamb
fonte
7
isso funcionou muito bem para mim (Windows XP SP3). IMHO esta é a maneira mais elegante de todos aqui proposto, usando apenas as ferramentas fornecido com o Windows
hello_earth
2
Eu tive um problema de sintaxe com esta linha de comando. Eu mudei para tasklist /FI "IMAGENAME eq winword.exe" 2>NUL | find /I /N "winword.exe">NUL/ if %ERRORLEVEL%==1 goto wordnotrunningde modo a torná-lo funciona (suspeitar da citação em torno das Se as peças
Steve B
4
Lembre-se de que em versões do XP em outros idiomas os nomes dos filtros foram traduzidos em código, mas não na /?tela de ajuda . Então, por exemplo, IMAGENAMEna versão polonesa é NAZWA_OBRAZU.
rsk82
3
No Win7, tive que alterá-lo para tasklist /FI "IMAGENAME eq myapp.exe" /NH | find /I /N "myapp.exe" >NUL O primeiro NUL parece desnecessário, não tenho idéia para que serve o '2', o / NH é opcional.
Jan Doggen
12
A lista de tarefas sempre sai com o status 0, independentemente de encontrar ou não tarefas correspondentes, e é por isso que é inútil por si só. Como você precisa usar o find (ou findstr) para verificar sua saída de qualquer maneira, não faz sentido usar os filtros da lista de tarefas. Basta fazer a lista de tarefas | encontre "myprog.exe"> nul: && vá para o encontrado ou algo assim. Você pode precisar da opção / v (detalhada) na lista de tarefas.
Denis Howe
61

Aqui está como eu resolvi isso:

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

O exemplo acima abrirá o Bloco de Notas se ainda não estiver em execução.

Editar: observe que isso não encontrará aplicativos ocultos da lista de tarefas. Isso incluirá todas as tarefas agendadas em execução como um usuário diferente, pois elas serão ocultadas automaticamente.

Matt Lacey
fonte
2
Alterar o formato da lista de tarefas para CSV ou qualquer coisa, menos a tabela, é importante porque o layout padrão da tabela de tarefas (tabela) trunca nomes longos de imagens que quebram a lógica.
Scott White
4
Esta solução não funcionará no Vista porque o TASKLIST produz alguma saída, mesmo que o processo não seja encontrado. Eu presumo que o mesmo é verdadeiro para o Windows 7.
dbenham
não funciona no Windows 10. search.log contém "INFO: Nenhuma tarefa em execução corresponde aos critérios especificados". e nenhum bloco de notas é iniciado #
Sergey
46

Eu gosto da solução do Chaosmaster! Mas eu olhei para uma solução que não iniciar outro programa externo (como Find.exe ou findstr.exe ). Então, adicionei a idéia da solução de Matt Lacey, que cria um arquivo temporário também evitável. No final, pude encontrar uma solução bastante simples, então eu a compartilho ...

SETLOCAL EnableExtensions
set EXE=myprog.exe
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF %%x == %EXE% goto FOUND
echo Not running
goto FIN
:FOUND
echo Running
:FIN

Isso está funcionando muito bem para mim ...

TrueY
fonte
Esta solução funciona bem testada no Windows 8.1. Notei que faz distinção entre maiúsculas e minúsculas.
oliver-clare
@ LordScree Enquanto trabalho nos sistemas un * x, a sensibilidade é boa para mim! Até defini o sistema de arquivos para ativar os nomes de arquivo que diferenciam maiúsculas de minúsculas. ;)
TrueY
Funciona bem para mim - testado no Windows 7 x64
Sr. Rubix
Isso não funciona se o aplicativo tiver um espaço no nome, pois% x acaba fazendo parte do nome do aplicativo até o primeiro espaço.
22419 Chris
Uma solução possível seria verificar se o aplicativo não foi encontrado, verificando se% x == INFO: mas não sei em quais versões do Windows isso funcionaria ou se há uma solução melhor.
22419 Chris
21

A sugestão do npocmaka de usar o QPROCESS em vez do TASKLIST é ótima, mas sua resposta é tão grande e complexa que me sinto obrigado a postar uma versão bastante simplificada do mesmo, que eu acho que resolverá o problema da maioria dos usuários não avançados:

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

O código acima foi testado no Windows 7, com um usuário com direitos de administrador.

aldemarcalazans
fonte
Eu apenas usei essa idéia para parar um processo automatizado de disparar duas vezes e funcionou como um encanto!
Davy C
Devo dizer que, diferentemente deste comando, as soluções da lista de tarefas não apenas parecem muito complicadas para uma consulta tão simples, mas também executam um segundo ou mais e usam toneladas de CPU! Isso é muito melhor, também funcionou sem permissões de administrador (Windows Server 2012).
Eugene Marin
Essa parece ser a melhor e mais simples solução (pelo menos para mim), pois funciona como está quando o aplicativo tem espaços no nome. Estou curioso para saber quais são as limitações desta solução e por que ela não tem mais votos.
22419 Chris
20

No Windows, você pode usar a WMI (Instrumentação de Gerenciamento do Windows) para garantir que nenhum aplicativo com a linha de comando especificada seja iniciado, por exemplo:

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)

vtrz
fonte
Observe que o WMIC requer privilégios administrativos; se você não o tiver, então Only the administrator group members can use WMIC.EXE.seguido porReason:Win32 Error: Access is denied.
Jeroen Wiert Pluimers
eu acho que essa é a melhor solução, porque wmic dá-lhe uma linha de comando completa lançado e milion outras informações ...
Glavic
13
TASKLIST | FINDSTR ProgramName || START "" "Path\ProgramName.exe"
Riccardo La Marca
fonte
3
Isso realmente funciona muito bem. Simples! Lembre-se de que diferencia maiúsculas de minúsculas, a menos que você adicione /i.
25419 Jason
8

Eu uso o PV.exe em http://www.teamcti.com/pview/prcview.htm instalado em Program Files \ PV com um arquivo em lotes como este:

@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

fonte
1
isso funciona para mim no Windows 7. A segunda linha é o diretório que contém o programa, não o próprio programa.
Fabio Cionini 16/04
8

A resposta de TrueY parecia a solução mais elegante; no entanto, eu tinha que fazer algumas brincadeiras, porque não entendia exatamente o que estava acontecendo. Deixe-me esclarecer as coisas, espero economizar algum tempo para a próxima pessoa.

Resposta modificada de 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!

Enfim, espero que ajude. Eu sei que às vezes ler lote / linha de comando pode ser meio confuso, às vezes, se você é um novato, como eu.

kayleeFrye_onDeck
fonte
6

A resposta fornecida por Matt Lacey funciona no Windows XP. No entanto, no Windows Server 2003, a linha

 tasklist /FI "IMAGENAME eq notepad.exe" /FO CSV > search.log

retorna

INFO: Nenhuma tarefa em execução corresponde aos critérios especificados.

que é então lido enquanto o processo está em execução.

Como não tenho muita experiência com scripts em lote, minha ação é procurar o nome do processo no search.logarquivo e bombear os resultados para outro arquivo e procurar por qualquer saída.

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

Espero que isto ajude alguém.

benmod
fonte
Isso funciona no Win 2008. +1 em Nenhuma tarefa em execução que atenda aos critérios especificados.
Mangesh Pimpalkar
5

I como o WMICe TASKLISTferramentas, mas eles não estão disponíveis na home / edições básicas de windows.Another maneira é usar QPROCESScomandos disponíveis em quase todos os máquina Windows (para os que têm serviços de terminal - Eu acho que só tem a ganhar XP sem SP2, assim practialy cada máquina de janelas):

@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

QPROCESSO comando não é tão poderoso quanto TASKLISTé limitado e mostra apenas 12 símbolos do nome do processo, mas deve ser levado em consideração se TASKLISTnão estiver disponível.

Uso mais simples em que ele usa o nome se o processo como argumento (o .exesufixo é obrigatório neste caso em que você passa o nome do executável):

@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

A diferença entre duas formas de QPROCESSuso é que QPROCESS *listará todos os processos e QPROCESS some.exefiltrará apenas os processos para o usuário atual.

Usar WMIobjetos através do Windows Script Host Exe em vez de WMICtambém é uma opção. Ele deve ser executado também em todas as máquinas Windows (excluindo aquelas em que o WSH está desativado, mas este é um caso raro) .Aqui está o arquivo bat que lista todos os processos através do WMI classes e pode ser usado no lugar do QPROCESSscript acima (é um híbrido jscript / bat e deve ser salvo como .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 );
}

E uma modificação que verificará se um processo está em execução:

@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 );
}

As duas opções podem ser usadas em máquinas que não possuem TASKLIST.

A técnica final está usando MSHTA. Isso será executado em todas as máquinas Windows a partir do XP e acima e não depende das configurações do host de scripts do Windows. a chamada de MSHTApoderia reduzir um pouco o desempenho (novamente deve ser salvo como bastão):

@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();
npocmaka
fonte
2

Não sei como fazer isso com o CMD embutido, mas se você tiver grep, tente o seguinte:

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

Apenas mencionando, se o nome da sua tarefa for realmente longo, ele não aparecerá na íntegra no tasklistresultado; portanto, pode ser mais seguro (além da localização) verificar o oposto.

Variação desta resposta :

:: 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
)
drzaus
fonte
0

Estou assumindo janelas aqui. Portanto, você precisará usar o WMI para obter essas informações. Confira os arquivos da Equipe de Scripts para ver muitos exemplos de como usar o WMI a partir de um script.

Eu não
fonte
0

Eu usei o script fornecido por Matt (02-10-2008). A única coisa com a qual tive problemas foi que ele não excluiria o search.logarquivo. Espero porque precisei ir cdpara outro local para iniciar meu programa. Eu cdvoltei para onde o arquivo BAT search.logestá e , mas ele ainda não foi excluído. Então, resolvi isso excluindo o search.logarquivo primeiro e não o último.

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
Nin
fonte
1
@ Sebastian: Há um pouco de informação extra adicionada aqui, então estou inclinado a deixar como resposta.
Bill the Lizard
0

Você deve verificar o nome do processo pai, consulte o artigo The Code Project sobre uma solução baseada em .NET ** .

Uma maneira não programática de verificar:

  1. Iniciar o Cmd.exe
  2. Iniciar um aplicativo (por exemplo, c:\windows\notepad.exe)
  3. Verifique as propriedades do processo Notepad.exe no Process Explorer
  4. Verificar processo pai (mostra cmd.exe)

O mesmo pode ser verificado obtendo o nome do processo pai.

prakash
fonte
0

Com base na resposta de vtrz e resposta de Samuel Renkert em um outro tópico , eu vim com o seguinte script que é executado somente %EXEC_CMD%se ele não estiver em execução:

@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.
)

Como foi dito antes, isso requer privilégios administrativos.

Calimo
fonte
não funcionou para mim e estou usando uma conta de administrador. Uma caixa do DOS aparece comNode - (computer name) ERROR: Description = Invalid query
khaverim
1
Funciona muito bem para mim.
Mark Duncan
1
Funciona muito bem para o Windows 7 aqui. Sem problemas.
galacticninja
0

Eu precisava de uma solução com uma nova tentativa. Esse código será executado até que o processo seja encontrado e depois o mate. Você pode definir um tempo limite ou qualquer coisa, se quiser.

Notas:

  • O ".exe" é obrigatório
  • Você pode tornar um arquivo executável com parâmetros, versão abaixo
    :: 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
        )

Correr com .\taskkill.bat ProgramToKill.exe

Patrick
fonte
-2

Normalmente, executo o seguinte comando no prompt do cmd para verificar se o meu program.exe está executando ou não:

tasklist | grep program
Rajeev Jayaswal
fonte