Pregunta

:: dostuff.bat
@echo off
:: insert long-running process call here
: End

¿Qué puedo añadir a este archivo por lotes para que sea terminar si ya se está ejecutando en otro proceso cuando se ha ejecutado?

¿Fue útil?

Solución

Bueno, si sólo puede haber exactamente una instancia cada vez, entonces es probable que pueda hacer esto mediante la creación de un archivo ficticio en alguna parte, probablemente en el directorio temporal:

copy NUL "%TEMP%\dostuff_is_doing_stuff.tmp"

A continuación, retire después de que haya terminado:

del "%TEMP%\dostuff_is_doing_stuff.tmp"

y en el inicio del archivo por lotes se puede comprobar si existe ese archivo y salida en consecuencia:

if exist "%TEMP%\dostuff_is_doing_stuff.tmp" (
    echo DoStuff is already running. Exiting ...
    exit /b 1
)

Del mismo modo, se puede hacer que cambiando el título de la ventana, que también debe ser más robusto frente a un Ctrl + C 'ed o se haya estrellado archivo por lotes.

Configurar el título:

title DoStuff

Re-colocó después:

title Not doing stuff

Comprobar que:

tasklist /FI "WINDOWTITLE eq DoStuff"

Sin embargo, esto tiene un problema: Cuando se ejecuta cmd como administrador obtendrá "Administrador: DoStuff" como el título. Que no se corresponde más con tasklist. Puede cortar-resolverlo comprobar también la "Administrador: DoStuff", pero que puede tener un aspecto diferente dependiendo del idioma de Windows interfaz de usuario, por lo que probablemente no es la mejor solución

Otros consejos

No hay manera de hacer esto de una manera limpia sin necesidad de utilizar una herramienta externa a medida (Usted quiere algo que crea un mutex y corre (y espera) el comando externo, de esta manera, si el proceso se mató, el mutex muere con él)

Lote:

@echo off
echo starting long running process
REM calling dir here just to get a long running operation
onecmd.exe cmd.exe /C dir /S /B \*
echo done...bye

C ++ ayudante de aplicación:

//Minimal error checking in this sample ;)
#include <Windows.h>
#include <TCHAR.h>

int main()
{
    const TCHAR myguid[]=_T("50D6C9DA-8135-42de-ACFE-EC223C214DD7");
    PROCESS_INFORMATION pi;
    STARTUPINFO si={sizeof(STARTUPINFO)};

    HANDLE mutex=CreateMutex(NULL,true,myguid);
    DWORD gle=GetLastError();
    if (!mutex || gle==ERROR_ALREADY_EXISTS) 
    {
        CloseHandle(mutex);
        return gle;
    }

    TCHAR*p=GetCommandLine();
    if (*p=='"' && *(++p)) {
        while (*p && *p!='"')++p;if (*p)++p;
    }
    else 
        while (*p && *p!=' ')++p;
    while(*p==' ')++p;

    if (CreateProcess(0,p,0,0,false,0,0,0,&si,&pi)) 
    {
        DWORD ec;
        WaitForSingleObject(pi.hProcess,INFINITE);
        GetExitCodeProcess(pi.hProcess,&ec);
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
        return ec;
    }
    gle=GetLastError();
    CloseHandle(mutex);
    return gle;
}

sobre todo no puede en manera amable.

En primer lugar, porque no es trivial para hacerlo. Usted tiene que encontrar el proceso de cmd.exe correcta cuando, en general, no es muy fácil de "hacer todas las cosas bien".

En segundo lugar, la terminación puede ser no es suficiente para detener el guión, porque una secuencia de comandos puede ejecutar otro script en el ciclo, por lo que sólo terminando uno no va a conducir a la terminación completa de otro. Más encima, puede conducir a una ejecución roto porque hay que terminar todo el proceso de árbol desde la raíz "atómicamente" para detener la ejecución adecuada.

En lugar de "búsqueda de suspender" se puede simplemente "no se ejecutará si ya se está ejecutando". La técnica es la misma que en Unix shell scripting:. Tratar de crear algún directorio único y bloquearla de la eliminación de la redirección de escritura en un archivo en ese directorio

Estoy utilizando el nombres de script algo así como exec_once_or_exit.bat:

@echo off

setlocal

set "LOCK_DIR_NAME_SUFFIX=%DATE%_%TIME%"
set "LOCK_DIR_NAME_SUFFIX=%LOCK_DIR_NAME_SUFFIX::=_%"
set "LOCK_DIR_NAME_SUFFIX=%LOCK_DIR_NAME_SUFFIX:/=_%"
set "LOCK_DIR_NAME_SUFFIX=%LOCK_DIR_NAME_SUFFIX:-=_%"
set "LOCK_DIR_NAME_SUFFIX=%LOCK_DIR_NAME_SUFFIX:.=_%"
set "LOCK_DIR_NAME_SUFFIX=%LOCK_DIR_NAME_SUFFIX:,=_%"
set LASTERROR=0

rem cleanup if leaked by crash or ctrl-c, won't be removed if already acquired because of write redirection lock
rmdir /S /Q "%TEMP%\lock_%~1" >nul 2>&1

mkdir "%TEMP%\lock_%~1" && (
  rem IMPL to use "goto :EOF" in next command instead of "exit /b %ERRORLEVEL%" under "block" command - "( )"
  call :IMPL %%*
  goto :EOF
)
exit /b -1024

:IMPL
rem call IMPL2 to recover exit code from commands like "exit /b"
call :IMPL2 %%* 9> "%TEMP%\lock_%~1\lock0_%LOCK_DIR_NAME_SUFFIX%.txt"
set LASTERROR=%ERRORLEVEL%
rmdir /S /Q "%TEMP%\lock_%~1"
exit /b %LASTERROR%

:IMPL2
rem a batch script must be always call over the "call" prefix
if "%~n2" == "bat" call %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9 && goto :EOF
if not "%~n2" == "bat" (
  %2 %3 %4 %5 %6 %7 %8 %9
)
goto :EOF

Uso:

exec_once_or_exit.bat <UniqueNameForLock> <PathToExecutable> <8Arguments>
exec_once_or_exit.bat <UniqueNameForLock> <BatchCommand(s)>

Explicación:

El comando mkdir no devolverá el código de salida cero si el directorio ya existe o no se puede crear, por alguna razón, y 0 si creado.

El LOCK_DIR_NAME_SUFFIX se utiliza para tener nombre único para el archivo en el directorio. Es usos todos estos reemplazos más caracteres específicos ya que el formato% FECHA% y% TIEMPO% de esa variable en función del formato de fecha y hora en la página ventanas localización.

Redirección sobre el ID de flujo 9 se utiliza para bloquear el archivo en el directorio de escritura y así bloquea el directorio matriz misma de la eliminación. Si la corriente por alguna razón no se puede redirigir a continuación, la secuencia de comandos termina inmediatamente por el cmd.exe w / o la ejecución adicional que es suficiente para la exclusión mutua de ejecución. Por lo tanto, debido a que el cambio de dirección ocurre antes de la ejecución no hay temor de que algo puede ejecutar antes de la redirección.

Si choque o ctrl-C se sucedieron a continuación, el directorio se mantendrá en el almacenamiento (HDD, SSD, que siempre otro), por lo que la limpieza que en ese caso los tryes script para eliminar todo el directorio con todos los archivos dentro antes la mkdir.

Lo único que puede pasar aquí es que el mal no se puede adquirir la ejecución que no parece tan frecuente que suceda. Al menos es mejor que "más de uno a la vez".

dos archivos:

-START.BAT-

if exist "%TEMP%\dostuff_is_doing_stuff.tmp" (   
exit /b 1
)

copy NULL "%TEMP%\dostuff_is_doing_stuff.tmp"

cmd /K COMMANDS.bat

-COMMANDS.BAT -

REM ...do something

REM ...do something

REM ...do something    

DEL "%TEMP%\dostuff_is_doing_stuff.tmp"

Inicio> Ejecutar:

echo cmd / k - ^ | -.> - Bat & -

viola las reglas porque (muchos) más de una instancia de carreras simultaneously- pero es una forma divertida de conseguir comida gratis:. Apostar su almuerzo compañero de trabajo que no puede matarlo sin frío arranque

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top