Identify running instances of a batch file
batch-file, batch-processing
Solution
wmz identified a number of errors in the OP's code, and also has an excellent suggestion to use a lock file for concurrency control.
Below is a robust batch solution that uses a lock file to prevent multiple instances of the batch file from running at the same time. It uses a temporary lock file for the concurrency control. The mere presence of the lock file does NOT stop the script from running. The script will only fail if another process has an exclusive lock on the lock file. This is important in case the script should crash or be killed without deleting the lock file. The next process to run the script will still succeed because the file is no longer locked.
This script assumes the script is installed on a local drive. It allows only one instance for the entire machine. There are lots of variations to control the amount of concurrency allowed. For example, incorporating the %USERNAME% into the lock file name would allow one instance per user in a network environment. Incorporating %COMPUTERNAME% in the name would allow one instance per machine in a network environment.
@echo off
setlocal
:: save parameters to variables here as needed
set "param1=%~1"
:: etc.
:: Redirect an unused file handle for an entire code block to a lock file.
:: The batch file will maintain a lock on the file until the code block
:: ends or until the process is killed. The main code is called from
:: within the block. The first process to run this script will succeed.
:: Subsequent attempts will fail as long as the original is still running.
set "started="
9>"%~f0.lock" (
set "started=1"
call :start
)
if defined started (
del "%~f0.lock" >nul 2>nul
) else (
echo Process aborted: "%~f0" is already running
)
exit /b
:start
:: The main program appears below
:: All this script does is PAUSE so we can see what happens if
:: the script is run multiple times simultaneously.
pause
exit /b
EDIT
The error message "The process cannot access the file because it is being used by another process." can be suppressed by redirecting stderr output to nul in an outer block.
2>nul (
9>"%~f0.lock" (
set "started=1"
call :start
)
)
The problem with the above is that all error messages for the main program will also be suppressed. That can be fixed by 1st saving the current definition of stderr to another unused file handle, and then adding yet another inner block that redirects stderr back to the saved file handle.
8>&2 2>nul (
9>"%~f0.lock" (
2>&8 (
set "started=1"
call :start
)
)
)
Problem
These are not working for me. Any help to definitelly corret the four examples below ? The EXAMPLE01 just echoes "continue", even if I have three CMD.exe opened. ---------- EXAMPLE 01 ------------ ``` @echo off wmic process where name="cmd.exe" | find "cmd.exe" /c SET ERRORLEVEL=value if "%value%" GTR 1 ( ECHO This batch is not first ECHO quitting ... ) if "%value%" LSS 2 ECHO continue ``` I am getting the "unexpected i error" message in the EXAMPLE 02! ----------- EXAMPLE 02 ------- ``` @echo off FOR /F "usebackq tokens=2" %i IN (`tasklist ^| findstr /r /b "cmd.exe"`) DO taskkill /pid %%i ``` I am getting the "is first" message in the EXAMPLE 03, even with three CMD.exe opened! ----------- EXAMPLE 03 ------- ``` @echo off wmic process where name="cmd.exe" | find "cmd.exe" /c if "%errorlevel%" LEQ 1 echo CMD is first if "%errorlevel%" GTR 1 echo CMD is already running ``` It is also possible that I will not have access to the Wmic command at work, so, another possibility is found in the EXAMPLE 04 ... but to no avail. ----------- EXAMPLE 04 ------- ``` @echo off Tasklist /FI "IMAGENAME eq cmd.exe" 2>NUL | find /I /N "cmd.exe">NUL if "%ERRORLEVEL%"==0 do (goto Use) else (goto Cont) :Cont ECHO Only one instance running pause :Use echo Application running already. Close this window ``` Kind regards, Maleck