I discovered a minor bug in my code - Percent is a legal character in a file path, and it is also the wildcard character in a WMIC LIKE query. So any percents within the UID should be encoded.
Code: Select all
@echo off
:getPID [RtnVar]
::
:: Store the Process ID (PID) of the currently running script in environment variable
:: RtnVar. If called without any argument, then simply write the PID to stdout.
::
setlocal disableDelayedExpansion
:getLock
set "lock=%temp%\%~nx0.%time::=.%.lock"
set "uid=%lock:\=:b%"
set "uid=%uid:,=:c%"
set "uid=%uid:'=:q%"
set "uid=%uid:_=:u%"
setlocal enableDelayedExpansion
set "uid=!uid:%%=:p!"
endlocal & set "uid=%uid%"
2>nul ( 9>"%lock%" (
for /f "skip=1 delims=" %%A in (
'wmic process where "name='cmd.exe' and CommandLine like '%%<%uid%>%%'" get ParentProcessID'
) do for /f "delims=" %%B in ("%%A") do set "PID=%%B"
(call )
))||goto :getLock
del "%lock%" 2>nul
endlocal & if "%~1" equ "" (echo(%PID%) else set "%~1=%PID%"
exit /b
siberia-man wrote:1. Could you explain in more details why do you transform %lock% into %uid%? I see the resulting command is as follows
Code: Select all
wmic process where "name='cmd.exe' and CommandLine like '%<c::bTemp:bcmdpid.bat.23.19.21.93.lock>%'" get ParentProcessID
but I can't understand how
CommandLine like '...' can help in searching our cmd instance? How does it work?
The WMIC command is executed via a new cmd.exe launched by FOR /F. The WMIC command is performing a search. The search is passed in as a parameter. The search parameter must first be passed as a parameter through cmd - somethiing like:
Code: Select all
C:\Windows\system32\cmd.exe /c wmic process where "name='cmd.exe' and CommandLine like '%<c::bTemp:bcmdpid.bat.23.19.21.93.lock>%'" get ParentProcessID
So the uid we are looking for is part of the command line - the query is effectively searching for itself
Some characters that may appear in the lock file path cause problems in a WMIC query - namely backslash, comma, and single quote. So they must be encoded. Also, the underscore and percent characters are valid path characters, but they are also wildcards for the LIKE operator. We want to treat them as literals, not wildcards, so they also must be encoded.
siberia-man wrote:2. Why do you clean the %TIME% variable? Also I think only setlocal is enough. Correct?
The time is incorporated into the temporary lock file name - but %TIME% contains colons, and colons are not allowed in file names. So I substitute a dot for each colon.
My code requires that delayed expansion be disabled when %~nx0 is expanded, just in case the batch script name contains an exclamation point. Delayed expansion is typically disabled when a script it started, but there are no guarantees - I explicitly disable it just to be sure.
Yury wrote:dbenham wrote:Yury wrote:dbenham, what should I do with your code to run it in a batch file that has the name "&ABC.bat"?
I put my posted code within a file named "&abc.bat" and it works fine for me. I can run the script using either CALL "&ABC" or CALL ^&ABC.
I found the reason. I tried to create a lock file in the directory from where the batch file was launched:
Code:
set "lock=%~nx0.%time::=.%.lock"
.
But the question remains: what to do with an ampersand at the beginning of the file name in this case?
I don't understand where you are having problems. My code simply works, even if there is an ampersand in the name. What isn't working for your? Are you using my code?
Dave Benham