windows - running - Cómo comprobar si un proceso se está ejecutando a través de un script por lotes
tasklist find (17)
¿Cómo puedo verificar si una aplicación se está ejecutando desde un archivo por lotes (well cmd)?
Necesito no iniciar otra instancia si ya hay un programa en ejecución. (No puedo cambiar la aplicación para que sea solo una instancia).
También la aplicación podría estar ejecutándose como cualquier usuario.
¡Me gusta la solución de Chaosmaster! Pero busqué una solución que no inicia otro programa externo (como find.exe o findstr.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 ...
Así es como lo he resuelto:
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 Notepad si aún no se está ejecutando.
Editar: Tenga en cuenta que esto no encontrará aplicaciones ocultas en la lista de tareas. Esto incluirá cualquier tarea programada que se ejecute como un usuario diferente, ya que se ocultan automáticamente.
Bajo Windows, puede usar Windows Management Instrumentation (WMI) para asegurarse de que no se inicie ninguna aplicación con la línea de comandos 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)
Debe verificar el nombre del proceso principal, consulte el artículo de The Code Project sobre una solución basada en .NET ** .
Una forma no programática de comprobar:
- Ejecutar Cmd.exe
- Iniciar una aplicación (por ejemplo,
c:/windows/notepad.exe
) - Compruebe las propiedades del proceso Notepad.exe en Process Explorer
- Compruebe el proceso principal (Esto muestra cmd.exe)
Lo mismo puede verificarse obteniendo el nombre del proceso padre.
Estoy asumiendo ventanas aquí. Por lo tanto, deberá utilizar WMI para obtener esa información. Consulte los archives The Scripting Guy para ver muchos ejemplos sobre cómo usar WMI desde un script.
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
INFO: No se están ejecutando tareas que coincidan con los criterios especificados.
que luego se lee como el proceso se está ejecutando.
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 archivo search.log
y bombear los resultados en otro archivo y buscar cualquier resultado.
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.
La respuesta de TrueY parecía la solución más elegante, sin embargo, tuve que hacer un poco de confusión porque no entendía qué estaba pasando exactamente. Permítame aclarar las cosas para, con suerte, ahorrar algo de tiempo para la siguiente 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 lotes / líneas de comando puede ser un poco confuso a veces si eres un novato, como yo.
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.
Me gustan las herramientas WMIC
y TASKLIST
pero no están disponibles en las ediciones de inicio / básicas de QPROCESS
forma es usar el comando QPROCESS
disponible en casi todas las máquinas con Windows (para las que tienen servicios de terminal, creo que solo se gana XP sin SP2) tan practialy cada máquina de 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
comando QPROCESS
no es tan poderoso como TASKLIST
y se limita a mostrar solo 12 símbolos del nombre del proceso, pero debe tenerse en cuenta si TASKLIST
no está disponible.
Uso más simple donde usa el nombre si el proceso es un argumento (el sufijo .exe
es obligatorio en este caso donde se pasa el nombre del 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 uso de QPROCESS
es que QPROCESS *
todos los procesos, mientras que QPROCESS some.exe
filtrará solo los procesos para el usuario actual.
El uso de objetos de WMI
través de Windows Exe de host de script en lugar de WMIC
también es una opción. También debe ejecutarse en todas las máquinas de Windows (excluyendo aquellas en las que el WSH está desactivado, pero este es un caso raro). a través de clases de WMI y se puede utilizar en lugar de QPROCESS
en 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 un proceso se está ejecutando:
@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 técnica definitiva es usar MSHTA
. Esto se ejecutará en todas las máquinas Windows desde XP y superiores, y no depende de la configuración del host del script de Windows. MSHTA
embargo, la llamada de MSHTA
podría reducir un poco el rendimiento (de nuevo debería 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();
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"
Normalmente ejecuto el siguiente comando en el indicador de cmd para verificar si mi program.exe se está ejecutando o no:
tasklist | grep program
Otra posibilidad que se me ocurrió, inspirada al usar grep , es:
tasklist /FI "IMAGENAME eq myapp.exe" 2>NUL | find /I /N "myapp.exe">NUL
if "%ERRORLEVEL%"=="0" echo Program is running
No es necesario guardar un archivo adicional, así que prefiero este método.
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 solo ejecuta %EXEC_CMD%
si aún 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.
Solo mencionando, si el nombre de su tarea es realmente largo, entonces no aparecerá en su totalidad en el resultado de la tasklist
, 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
)
Uso PV.exe de http://www.teamcti.com/pview/prcview.htm instalado en Archivos de programa / 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
Utilicé el guión proporcionado por Matt (2008-10-02). Lo único con lo que tuve problemas fue que no eliminaría el archivo search.log
. Espero porque tuve que cd
a otra ubicación para iniciar mi programa. Volví a la search.log
estaban el archivo BAT y search.log
, pero aún no se eliminaría. Así que resolví eso eliminando el archivo search.log
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
TASKLIST | FINDSTR ProgramName || START "" "Path/ProgramName.exe"