Cómo verificar si un proceso se ejecuta a través de un script por lotes

260

¿Cómo puedo verificar si una aplicación se ejecuta desde un archivo por lotes (cmd)?

No necesito iniciar otra instancia si ya se está ejecutando un programa. (No puedo cambiar la aplicación para que sea solo una instancia).

Además, la aplicación podría estar ejecutándose como cualquier usuario.

Matt Lacey
fuente
12
duplicado de una pregunta hecha cinco años después?
Matt Lacey
@ LưuVĩnhPhúc ni siquiera están relativamente cerca.
Cardenal - Restablece a Mónica el
@JackKirby, ¿quién dijo que no está relacionado?
phuclv
3
@oopsdazie, sí, puedo estar equivocado en este caso, pero la regla general es mantener la pregunta con la mejor colección de respuestas y cerrar la otra como un duplicado , independientemente del tiempo
phuclv

Respuestas:

330

Otra posibilidad que se me ocurrió, inspirada en el uso de grep , es:

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

No necesita guardar un archivo adicional, así que prefiero este método.

pkamb
fuente
77
Esto funcionó muy bien para mí (Windows XP SP3). En mi humilde opinión esta es la forma más elegante de todos los que aquí se propone, utilizando sólo las herramientas que vienen con ventanas
hello_earth
2
Tuve un problema de sintaxis con esta línea de comando. Lo cambié a tasklist /FI "IMAGENAME eq winword.exe" 2>NUL | find /I /N "winword.exe">NUL/ if %ERRORLEVEL%==1 goto wordnotrunningpara que funcione (sospechando la cita alrededor de las partes if
Steve B
44
Recuerde que en las versiones de XP de otros idiomas, los nombres de los filtros se tradujeron en código pero no en la /?pantalla de ayuda . Así, por ejemplo, IMAGENAMEen la versión polaca es NAZWA_OBRAZU.
rsk82
3
Bajo Win7 tuve que cambiarlo a tasklist /FI "IMAGENAME eq myapp.exe" /NH | find /I /N "myapp.exe" >NUL El primer NUL parece innecesario, no tengo idea de para qué sirve el '2', el / NH es opcional.
Jan Doggen
12
tasklist siempre sale con el estado 0 independientemente de si encuentra o no tareas coincidentes, por lo que es inútil por sí solo. Como de todos modos tiene que usar find (o findtr) para verificar su salida, no tiene sentido usar los filtros de la lista de tareas. Solo haz la lista de tareas | busque "myprog.exe"> nul: && goto foundit o somesuch. Es posible que necesite la opción / v (detallado) para la lista de tareas.
Denis Howe
61

Así es como lo resolví:

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

Lo anterior abrirá el Bloc de notas si aún no se está ejecutando.

Editar: tenga en cuenta que esto no encontrará aplicaciones ocultas de la lista de tareas. Esto incluirá cualquier tarea programada que se ejecute como un usuario diferente, ya que se oculta automáticamente.

Matt Lacey
fuente
2
Cambiar el formato de la lista de tareas a CSV o cualquier otra cosa que no sea la tabla es importante porque el diseño predeterminado de la lista de tareas (tabla) trunca los nombres de imagen largos, lo que rompe la lógica.
Scott White
44
Esta solución no funcionará en Vista porque TASKLIST produce algunos resultados incluso si no se encuentra el proceso. Supongo que lo mismo es cierto para Windows 7.
dbenham
no funciona en Windows 10. search.log contiene "INFORMACIÓN: no se están ejecutando tareas que coincidan con los criterios especificados". y no se inicia ningún bloc de notas
Sergey
46

¡Me gusta la solución de Chaosmaster! Pero busqué una solución que no inicie otro programa externo (como find.exe o findtr.exe ). Así que agregué la idea de la solución de Matt Lacey, que crea un archivo temporal también evitable. Al final pude encontrar una solución bastante simple, así que la comparto ...

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

Esto me está funcionando muy bien ...

Verdad
fuente
Esta solución funciona bien probada en Windows 8.1. Me di cuenta de que distingue entre mayúsculas y minúsculas.
oliver-clare
@LordScree ¡Mientras trabajo en sistemas un * x, la sensibilidad a mayúsculas y minúsculas es buena para mí! Incluso configuré el sistema de archivos para habilitar nombres de archivo sensibles a mayúsculas y minúsculas. ;)
TrueY
Funciona bien para mí - probado en Windows 7 X64
Mr Rubix
Esto no funciona si la aplicación tiene un espacio en el nombre ya que% x termina siendo parte del nombre de la aplicación hasta el primer espacio.
Chris
Una posible solución sería verificar si la aplicación no se encuentra en su lugar, verificando si% x == INFO: pero no sé en qué versiones de Windows funcionaría o si hay una solución mejor.
Chris
21

La sugerencia de npocmaka de usar QPROCESS en lugar de TASKLIST es genial, pero su respuesta es tan grande y compleja que me siento obligado a publicar una versión bastante simplificada que, supongo, resolverá el problema de la mayoría de los usuarios no avanzados:

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

El código anterior se probó en Windows 7, con un usuario con derechos de administrador.

aldemarcalazans
fuente
¡Acabo de usar esta idea para detener un proceso automatizado que se dispara dos veces y funcionó de maravilla!
Davy C
Debo decir que, a diferencia de este comando, las soluciones de la lista de tareas no solo parecen demasiado complicadas para una consulta tan simple, sino que también se ejecutan un segundo más o menos y usan toneladas de CPU. Esto es mucho mejor, también funcionó sin permisos de administrador (Windows Server 2012).
Eugene Marin
Esta parece ser la mejor y más simple solución (al menos para mí), ya que funciona tal como está cuando la aplicación tiene espacios en el nombre. Tengo curiosidad por saber cuáles son las limitaciones de esta solución y por qué no tiene más votos.
Chris
20

En Windows, puede usar el Instrumental de administración de Windows (WMI) para asegurarse de que no se inicien aplicaciones con la línea de comando especificada, por ejemplo:

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
fuente
Tenga en cuenta que WMIC requiere privilegios administrativos; si no lo tiene, a continuación, Only the administrator group members can use WMIC.EXE.seguido porReason:Win32 Error: Access is denied.
Jeroen Wiert Pluimers
Creo que esta es la mejor solución, porque wmic le da una línea de comando completa lanzada y millones de otras informaciones ...
Glavić
14
TASKLIST | FINDSTR ProgramName || START "" "Path\ProgramName.exe"
Riccardo La Marca
fuente
3
Esto realmente funciona muy bien. ¡Sencillo! Solo tenga en cuenta que distingue entre mayúsculas y minúsculas a menos que agregue /i.
Jason
8

Uso PV.exe de http://www.teamcti.com/pview/prcview.htm instalado en Program Files \ PV con un archivo por 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

fuente
1
Esto funciona para mí en Windows 7. La segunda línea es el directorio que contiene el programa, no el programa en sí.
Fabio Cionini
8

La respuesta de TrueY parecía la solución más elegante, sin embargo, tuve que hacer algunos cambios porque no entendía exactamente qué estaba pasando. Permítanme aclarar las cosas para, con suerte, ahorrar algo de tiempo para la próxima persona.

Respuesta 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!

De todos modos, espero que ayude. Sé que a veces leer la línea de comandos / lote puede ser un poco confuso a veces si eres un novato, como yo.

kayleeFrye_onDeck
fuente
6

La respuesta proporcionada por Matt Lacey funciona para Windows XP. Sin embargo, en Windows Server 2003 la línea

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

devoluciones

INFORMACIÓN: no se están ejecutando tareas que coincidan con los criterios especificados.

que luego se lee mientras se ejecuta el proceso.

No tengo un montón de experiencia en secuencias de comandos por lotes, por lo que mi intención es buscar el nombre del proceso en el search.logarchivo y bombear los resultados a otro archivo y buscar cualquier salida.

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 esto ayude a alguien más.

benmod
fuente
Esto funciona para Win 2008. +1 para No se están ejecutando tareas que coincidan con los criterios especificados.
Mangesh Pimpalkar
5

Me gustan las herramientas WMICy TASKLIST, pero no están disponibles en las ediciones domésticas / básicas de QPROCESSWindows. Otra forma es usar el comando disponible en casi todas las máquinas Windows (para las que tienen servicios de terminal, creo que solo ganan XP sin SP2, así que prácticamente todos máquina de ventanas):

@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

QPROCESSEl comando no es tan poderoso TASKLISTy está limitado en mostrar solo 12 símbolos del nombre del proceso, pero debe tenerse en cuenta si TASKLISTno está disponible.

Uso más simple donde usa el nombre si el proceso es un argumento (el .exesufijo es obligatorio en este caso cuando pasa el nombre ejecutable):

@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

La diferencia entre dos formas de QPROCESSuso es que QPROCESS *enumerará todos los procesos y QPROCESS some.exefiltrará solo los procesos para el usuario actual.

El uso de WMIobjetos a través de Windows Script Host Exe en lugar de WMICtambién es una opción. Debería ejecutarse también en todas las máquinas Windows (excluyendo aquellas en las que WSH está apagado pero este es un caso raro). Aquí el archivo bat que enumera todos los procesos a través de WMI clases y se pueden usar en lugar de QPROCESSen el script anterior (es un híbrido jscript / bat y se debe guardar 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 );
}

Y una modificación que verificará si se está ejecutando un proceso:

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

Las dos opciones podrían usarse en máquinas que no tienen TASKLIST.

La última técnica es usar MSHTA. Esto se ejecutará en todas las máquinas con Windows desde XP y superiores y no depende de la configuración del host de script de Windows. Sin MSHTAembargo, la llamada de podría reducir un poco el rendimiento (nuevamente debe guardarse como 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();
npocmaka
fuente
2

No sé cómo hacerlo con CMD incorporado, pero si tiene grep , puede intentar lo siguiente:

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

Solo menciono, si el nombre de su tarea es realmente largo, entonces no aparecerá en su totalidad en el tasklistresultado, por lo que podría ser más seguro (aparte de la localización) verificar lo contrario.

Variación de esta respuesta :

:: 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
fuente
0

Estoy asumiendo ventanas aquí. Por lo tanto, deberá usar WMI para obtener esa información. Consulte los archivos de The Scripting Guy para obtener muchos ejemplos sobre cómo usar WMI desde un script.

Yo no
fuente
0

Utilicé el guión proporcionado por Matt (2008-10-02). Lo único con lo que tuve problemas fue que no eliminaría el search.logarchivo. Espero porque tuve que ir cda otro lugar para comenzar mi programa. Volví cda donde está el archivo BAT y estoy search.log, pero aún así no se eliminaría. Así que resolví eso eliminando el search.logarchivo primero en lugar de ú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
fuente
1
@Sebastian: Hay un poco de información adicional agregada aquí, así que me inclino a dejarla como respuesta.
Bill the Lizard
0

Usted debe verificar el nombre del proceso padre, véase El Proyecto Código artículo acerca de una solución basada en .NET ** .

Una forma no programática de verificar:

  1. Inicie Cmd.exe
  2. Inicie una aplicación (por ejemplo c:\windows\notepad.exe)
  3. Verifique las propiedades del proceso Notepad.exe en Process Explorer
  4. Verificar el proceso principal (Esto muestra cmd.exe)

Lo mismo se puede verificar obteniendo el nombre del proceso principal.

prakash
fuente
0

Sobre la base de la respuesta de vtrz y la respuesta de Samuel Renkert en otro tema , se me ocurrió la siguiente secuencia de comandos que sólo se ejecuta %EXEC_CMD%si no se está ejecutando:

@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 se dijo antes, esto requiere privilegios administrativos.

Calimo
fuente
no funcionó para mí y estoy usando una cuenta de administrador. Un cuadro de DOS aparece conNode - (computer name) ERROR: Description = Invalid query
khaverim
1
Funciona bien para mí.
Mark Duncan
1
Funciona muy bien para Windows 7 aquí. Sin problemas.
galacticninja el
0

Necesitaba una solución con un reintento. Este código se ejecutará hasta que se encuentre el proceso y luego lo matará. Puede establecer un tiempo de espera o cualquier cosa si lo desea.

Notas:

  • El ".exe" es obligatorio
  • Puede hacer que un archivo sea ejecutable con parámetros, versión a continuación
    :: 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
        )

Corre con .\taskkill.bat ProgramToKill.exe

Patricio
fuente
-2

Por lo general, ejecuto el siguiente comando en cmd prompt para verificar si mi program.exe se está ejecutando o no:

tasklist | grep program
Rajeev Jayaswal
fuente