Вопрос или проблема
Я пытаюсь найти способ получить собственный PID из командной строки (для последующего использования в bat-скриптах).
Пока единственный полезный способ, который я нашел, — использовать getpids.exe
отсюда: http://www.scheibli.com/projects/getpids/index.html, но я ищу команду, которая встроена в Windows.
Мне нужен “надёжный” способ. Без каких-либо предположений о том, что мой процесс является единственным cmd.exe или что-то подобное.
Поскольку ни одно из других решений не является надежным и встроенным, я решил предложить следующее решение, но обратите внимание, что вам нужно как-то парсить/сохранять результаты:
title mycmd
tasklist /v /fo csv | findstr /i "mycmd"
Использование PowerShell + WMI:
powershell (Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId
Использование WMIC:
for /f %a in ('wmic os get LocalDateTime ^| findstr [0-9]') do set NOW=%a
wmic process where "Name="wmic.exe" and CreationDate > '%NOW%'" get ParentProcessId | findstr [0-9]
(как всегда, удвойте знак %
с for
в пакетных файлах)
Расширяя ответ Тони Рота:
title uniqueTitle
for /f "tokens=2 USEBACKQ" %f IN (`tasklist /NH /FI "WINDOWTITLE eq uniqueTitle*"`) Do echo %f
Использование фильтра WINDOWTITLE исключает необходимость в pipe, так что вы можете вставить это в цикл for и назначить его переменной с помощью SET, если хотите:
title uniqueTitle
for /f "tokens=2 USEBACKQ" %f IN (`tasklist /NH /FI "WINDOWTITLE eq uniqueTitle*"`) Do set ourPID=%f
Удаление /v
делает процесс быстрее, а /NH
убирает строку заголовка. Вам нужен шаблон после "uniqueTitle"
, потому что заголовок окна на самом деле содержит текущую команду (иначе это бы продолжалось и продолжалось, если попытаться полностью его сопоставить).
Я считаю, что следующий способ надёжен, при условии, что пользователь имеет доступ к WMIC и TEMP указывает на правильный путь, где у пользователя есть права на запись. Это конечный результат совместной работы на http://www.dostips.com/forum/viewtopic.php?f=3&t=6133.
@echo off
:getPID [RtnVar]
::
:: Сохраняет ID процесса (PID) текущего выполняемого скрипта в переменной окружения RtnVar.
:: Если вызвано без аргументов, просто выводит PID на экран.
::
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" %%A in (
'wmic process where "name="cmd.exe" and CommandLine like '%%<%uid%>%%'" get ParentProcessID'
) do for %%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
Скрипт устанавливает эксклюзивный замок на временный файл, который включает текущее время в название. Коллизия может произойти только если два процесса с одинаковыми именами попытаются получить PID в тот же 0.01 секундный интервал времени, в этом случае только один из них будет успешным.
Любой процесс, который потерпит неудачу, будет повторено пробовать снова с новым путем замка, пока не добьется успеха.
Полный путь к файлу замка преобразуется в уникальный ID, который можно использовать в запросе WMIC. WMIC выполняется в команде FOR /F, то есть он выполняется в дочернем процессе cmd.exe, именно поэтому возвращается ParentProcessID процесса cmd.exe.
- Диспетчер задач Windows, нужно зайти в Вид -> Выбрать столбцы.. и выбрать PID.
- “tasklist /v” чтобы получить подробную информацию о задаче в командной строке.
- Process Explorer от live.sysinternals.com.
если вы знаете, что запущен только один cmd.exe, можно получить PID так:
for /F "tokens=1,2" %%i in ('tasklist /FI "IMAGENAME eq cmd.exe" /fo table /nh') do set pid=%%j
echo %pid%
Это должно сработать:
tasklist /v
Если вы хотите найти PID образа “notepad.exe”, следующий код вам подойдет:
for /F "tokens=1,2" %i in ('tasklist') do (
if "%i" equ "notepad.exe" (set x=%j)
)
echo %x%
Если у вас есть комплект ресурсов Windows 2003, прогоните его через qgrep, чтобы получить только нужную строку. Затем можно извлечь PID отсюда (это предполагает, что у вас запущен только один cmd в данный момент времени),
tasklist /v | qgrep cmd
cmd.exe 2040 RDP-Tcp#447 0 1,804 K В работе MACHINE\Administrator 0:00:00 Командная строка
Посмотрите на этот маленький трюк с пакетом. Он устанавливает заголовок cmd в специальное значение, а затем использует tasklist, чтобы найти его. Изобретательно
\\Greg
ЭТО КОРОТКИЙ ПУТЬ ПОЛУЧЕНИЯ ИДЕНТИФИКАТОРА ПРОЦЕССА ДЛЯ ОТКРЫТОГО CMD
tasklist /v /fi "imagename EQ cmd.exe" /FO LIST | FIND "PID:"
Это решение даст вам ТОЛЬКО идентификатор процесса, и никакой лишней информации, которую включает верхний ответ.
title mycmd
tasklist /v /fo csv | findstr /i "mycmd" > PIDinfo.txt
set /p PIDinfo=<PIDinfo.txt
set PID1=%PIDinfo:~11,5%
set PID2=%PIDinfo:~11,4%
if %PID2% gtr 8100 (
set PID=%PID2%
) else (
set PID=%PID1%
)
echo %PID%
Объяснение:
-не существует PID для cmd.exe, превышающего 18100, поэтому проверяем, больше ли PID2 8100, чтобы узнать, четырёхзначный или пятизначный номер
случай 1: пятизначный PID, например, 17504 имеет значение PID1 17504 и значение PID2 1750, так что используем PID1
случай 2: четырёхзначный PID, например, 8205 имеет значение PID1 8205″ и значение PID2 8205, так что используем PID2
случай 3: четырёхзначный PID, например, 4352 имеет значение PID1 4352″ и значение PID2 4352, так что используем PID2
вы можете попробовать getcmdPid.bat — это самокомпилируемое .net приложение, встроенное в bat-скрипт, и возвращает PID в виде errorlevel:
call getcmdPid
echo %errorlevel%
Чтобы получить PID для текущего пользователя, смотрите мой пример для перезапуска процесса проводника:
@echo off
for /F "tokens=1,2" %%i in ('tasklist /FI "IMAGENAME eq explorer.exe" /FI "USERNAME eq %USERDOMAIN%\%USERNAME%" /FO table /NH') do taskkill /F /PID %%j
start explorer.exe
Из вышеперечисленного я использовал это для получения текущего идентификатора процесса в batch-файле: для /f %a in (‘powershell “$proc=Get-WmiObject Win32_Process -Filter ProcessId=$PID; $proc.ParentProcessId”‘) do set PID=%a
Я нашел самое простое решение в комментарии от Nicolas Melay:
for /F %%a in ('PowerShell -ex bypass "(gwmi Win32_Process -f ProcessID=$((gwmi Win32_Process -f ProcessId=$PID).ParentProcessID)).ParentProcessID"') do set my_pid=%%a
Он использует PowerShell, чтобы получить PID родительского процесса, так как for
вводит дополнительный cmd.exe
.
Это раньше работало, похоже, не работает в чистом Windows 11, в Windows 10 с обновлением да! Непонятно, почему это должно было измениться.
for /f %%A in (
‘2^>nul wmic process where “ParentProcessID=%myPID% and not CommandLine like ‘%%<%UID%>%%'” get ProcessID’
) do for %%B in (%%A) do if “!PIDs: %%B =!” equ “!PIDs!” set “PID=%%B”
Ответ или решение
Чтобы узнать идентификатор процесса (PID) собственного экземпляра командной строки в Windows, можно воспользоваться несколькими подходами, которые не требуют установки дополнительных инструментов и используют встроенные возможности операционной системы. В этом детальном руководстве я опишу несколько способов, которые помогут вам получить PID надежно и эффективно.
Использование команды tasklist
-
Настройка уникального заголовка:
- Сначала измените заголовок окна командной строки на уникальное имя. Это поможет вам легко обнаружить процесс.
title MyUniqueCmdTitle
- Сначала измените заголовок окна командной строки на уникальное имя. Это поможет вам легко обнаружить процесс.
-
Получение PID с помощью
tasklist
:- Используйте
tasklist
с фильтром на заголовок окна, чтобы отфильтровать нужный процесс и получить его PID.for /f "tokens=2 USEBACKQ" %%f in (`tasklist /NH /FI "WINDOWTITLE eq MyUniqueCmdTitle*"`) do set MyPID=%%f echo %MyPID%
- Этот метод использует фильтр на заголовок, что исключает необходимость использования канала, упрощая интеграцию в скрипт.
- Используйте
Использование PowerShell
PowerShell предоставляет мощные возможности управления и может использоваться для извлечения информации о процессе.
- Запуск PowerShell из командной строки:
for /F %%a in ('PowerShell -Command "(Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId"') do set MyPID=%%a echo %MyPID%
- Эта команда запускает PowerShell, чтобы получить идентификатор родительского процесса текущего процесса командной строки, затем сохраняет его в переменной
MyPID
.
- Эта команда запускает PowerShell, чтобы получить идентификатор родительского процесса текущего процесса командной строки, затем сохраняет его в переменной
Использование WMIC (Windows Management Instrumentation Command)
WMIC — это мощный инструмент для управления системой Windows, который может использоваться для получения PID.
- Метод с WMIC:
for /f %a in ('wmic process where "name='cmd.exe'" get processid ^| findstr [0-9]') do set MyPID=%a echo %MyPID%
Заключение
Как видно, существует несколько способов получения PID своего процесса командной строки в Windows, используя встроенные инструменты. Каждый метод имеет свои преимущества и может подходить в зависимости от конкретных требований и контекста использования. Например, использование PowerShell может быть предпочтительным благодаря его гибкости, в то время как методы с tasklist
или WMIC легче интегрируются в стандартные командные сценарии.
При использовании этих методов важно учитывать права доступа и возможные ограничения в различных версиях Windows, чтобы обеспечить стабильную и корректную работу скрипта.