Как получить PID собственного процесса из командной строки в Windows

26

я пытаюсь найти способ получить свой собственный PID из командной строки (для последующего использования в скриптах bat), пока единственным полезным способом, который я нашел, было использование getpids.exe отсюда: http://www.scheibli.com/ projects / getpids / index.html, но я ищу команду, «встроенную» в windows

редактировать: я ищу способ «пуленепробиваемый» - никаких предположений о том, что мой процесс является единственным cmd.exe или что-то еще

radai
источник

Ответы:

36

Поскольку ни одно из других решений не является пуленепробиваемым и встроенным, я решил предложить следующее решение, но учтите, что вам нужно как-то проанализировать / сохранить результаты:

title mycmd
tasklist /v /fo csv | findstr /i "mycmd"
Тони Рот
источник
это действительно опрятно. я уверен, что текущее время + какое-то случайно сгенерированное число может быть установлено в качестве заголовка, чтобы приблизиться к пуленепробиваемости
radai
3
Не используйте% random% +% time%, если у вас есть планировщик, вызывающий ваш пакетный скрипт дважды одновременно. У меня была проблема, что один и тот же скрипт вызывался с разными параметрами одновременно. Семя для случайных было то же самое, и я столкнулся с коллизиями при создании временного каталога. Тогда не было никакого способа обработать ошибку при создании временного каталога. Короче говоря, если вы можете предположить, что ваш сценарий не будет запущен дважды, этот прием должен сработать.
Питер Шютце
Может быть (не глубоко проверено), что получение более точной временной метки (включая microseconds, а не 1/100 секунды, как в% времени%) будет более надежным в этом случае: wmic os get LocalDateTime(YearMonthDayHourMinuteSecond.Microsecond + Timezone). Если планировщик не может запустить две вещи в одну и ту же микросекунду ...
Готье Боальо
Это не будет работать, если процесс выполняется в другом сеансе на компьютере, поскольку заголовок отображается как N / A
FrinkTheBrave
Это дает PID родительского процесса.
access_granted
7

Я считаю, что следующее является пуленепробиваемым, при условии, что пользователь имеет доступ к WMIC и TEMP указывает на действительный путь, где у пользователя есть права на запись. Это конечный результат совместной работы на http://www.dostips.com/forum/viewtopic.php?f=3&t=6133 .

@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" %%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 секунды, и в этом случае только один будет успешным.

Любой сбойный процесс будет многократно возвращаться назад и повторять попытку с новым путем к файлу блокировки, пока он не будет успешным.

Полный путь к файлу блокировки преобразуется в уникальный идентификатор, который можно использовать в запросе WMIC. WMIC запускается в команде FOR / F, что означает, что он выполняется в дочернем процессе cmd.exe. Вот почему ParentProcessID процесса cmd.exe извлекается.

dbenham
источник
7

Расширяя ответ Тони Рота:

title uniqueTitle
for /f "tokens=2 USEBACKQ" %f IN (`tasklist /NH /FI "WINDOWTITLE eq uniqueTitle*"`) Do echo %f

Использование фильтра WINDOWTITLE позволяет избежать использования канала, поэтому вы можете поместить его в цикл for и назначить его переменной с помощью SET, если хотите:

title uniqueTitle
for /f "tokens=2 USEBACKQ" %f IN (`tasklist /NH /FI "WINDOWTITLE eq uniqueTitle*"`) Do set ourPID=%f

Удаление /vделает это быстрее, и /NHизбавляется от строки заголовка. Вам нужен подстановочный знак после, "uniqueTitle"потому что заголовок окна на самом деле содержит текущую команду (таким образом, он будет продолжаться и включаться, если вы попытаетесь полностью соответствовать ей).

Дэвид
источник
6

Использование PowerShell + WMI:

powershell (Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId
Николас Мелай
источник
Ницца; если у вас есть PowerShell Core , это становится еще проще (хотя ни одна из команд не будет быстрой ):pwsh -noprofile -c "(Get-Process -Id $PID).Parent.Id"
mklement
5
  1. Диспетчер задач Windows, вам нужно будет перейти к View -> Select Columns .. и выбрать PID.
  2. «tasklist / v» для получения подробной информации о задаче в командной строке.
  3. Обозреватель процессов из live.sysinternals.com .
Вивек Кумбхар
источник
2
@Vivek, из командной строки ... и вы дублируете ответы
WooYek
я просто дал все возможные варианты ... и не дублировал ... я мог бы также упомянуть PowerShell, но я ограничился, поскольку это не происходит по умолчанию в XP и 2003. Если это для ОС Vista и выше, да PowerShell был бы моим предпочтением ,
Вивек Кумбхар
5

если вы знаете, что запущен только один 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%
zumalifeguard
источник
Это звучит как невероятное предположение, ваш код может быть ненадежным
Рауль Салинас-Монтеагудо
Рауль, я понимаю, что ты говоришь. Во многих случаях это небезопасно, но в некоторых безопасно - например, в системе киоска или виртуальной
машине,
4

Это должно сделать трюк:

список задач / v

WooYek
источник
3

Если вы хотите найти PID imagename "notepad.exe", то вам подойдет следующий код:

for /F "tokens=1,2" %i in ('tasklist') do (
 if "%i" equ "notepad.exe" (set x=%j)
)
echo %x%
Minchurl
источник
2

Если у вас есть Windows 2003 Resource Kit, протолкните его через qgrep, чтобы получить нужную строку. Затем вы можете извлечь pid отсюда (это предполагает, что у вас запущен только один cmd за раз),

tasklist /v | qgrep cmd

cmd.exe 2040 RDP-Tcp#447 0 1,804 K Running MACHINE\Administrator  0:00:00 Command Prompt
Гуппи
источник
1

Взгляните на этот маленький трюк . Он устанавливает для заголовка cmd специальное значение, а затем использует список задач для его поиска. изобретательный

\\ Greg

uSlackr
источник
0

ЭТО КОРОТКИЙ СПОСОБ ПОЛУЧИТЬ ID ПРОЦЕССА ДЛЯ ОТКРЫТОГО CMD

tasklist /v /fi "imagename EQ cmd.exe" /FO LIST | FIND "PID:"
hollopost
источник
0

Этот ответ даст вам ТОЛЬКО идентификатор процесса, и ни один из дополнительных материалов, включенных в верхний ответ.

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, чтобы мы знали, является ли это 4-значное или 5-значное число

случай 1: 5-значный PID, такой как 17504, имеет значение PID1 17504 и значение PID2 1750, поэтому мы используем PID1

Случай 2: 4-значный PID, такой как 8205, имеет значение PID1 8205 "и значение PID2 8205, поэтому мы используем PID2

случай 3: 4-значный PID, такой как 4352, имеет значение PID1 4352 "и значение PID2 4352, поэтому мы используем PID2

Коллин Фокс
источник