コマンドプロンプトから自分自身の PID を取得する方法
コマンドプロンプトから自分自身の PID(プロセス ID)を取得する方法について、失敗例も含めて説明します。
動作確認環境
- Windows 10 Home 21H1, 64bit
tasklist のフィルター機能
Windows 付属の tasklist コマンドを使うと、実行中のプログラムとその PID などの一覧が表示されます。
C:\>tasklist
イメージ名 PID セッション名 セッション# メモリ使用量
========================= ======== ================ =========== ============
System Idle Process 0 Services 0 8 K
System 4 Services 0 1,408 K
Secure System 72 Services 0 23,320 K
Registry 132 Services 0 92,044 K
smss.exe 640 Services 0 1,096 K
csrss.exe 732 Services 0 4,436 K
wininit.exe 920 Services 0 5,784 K
......
cmd.exe 11428 Console 1 3,916 K
conhost.exe 11436 Console 1 18,316 K
cmd.exe 11492 Console 1 15,056 K
......
この tasklist を利用して現在のコマンドプロンプトの PID のみを抜き出せないかと、tasklist のヘルプを見てみました。
C:\>tasklist /?
TASKLIST [/S システム [/U ユーザー名 [/P [パスワード]]]]
[/M [モジュール] | /SVC | /V] [/FI フィルター] [/FO 形式] [/NH]
......
/FI フィルター フィルターによって指定された、与えられた条件に一致
するタスクを表示します。
......
フィルター:
フィルター名 有効な演算子 有効な値
......
WINDOWTITLE eq, ne ウィンドウ タイトル
......
すると「/FI フィルター」というオプションと「WINDOWTITLE」というフィルター名が見つかりました。指定したウィンドウタイトルをもつプロセスの情報のみを抜き出せるようです。これを使ってみます。
観察者効果
まず、「title」コマンドを使って自身のウィンドウタイトルをユニークな名前に変更します。複数のコマンドンプロンプトが同じウィンドウタイトルで起動している可能性があるためです。
ここでは単に「MyTitle」としましたが、本来は、日付 (%date%) や時刻 (%time%) や乱数 (%random%) を使ってユニーク性を高めたほうがよいでしょう。
C:\>title MyTitle
この状態でフィルター機能を使って「MyTitle」を検索してみます。しかし、何度探しても見つかりません。
C:\>tasklist /FI "WINDOWTITLE eq MyTitle"
情報: 指定された条件に一致するタスクは実行されていません。
メモ帳を起動し、「無題 – メモ帳」を検索すると、期待通り見つかります。
C:\>tasklist /FI "WINDOWTITLE eq 無題 - メモ帳"
イメージ名 PID セッション名 セッション# メモリ使用量
========================= ======== ================ =========== ============
notepad.exe 13176 Console 1 14,964 K
「tasklist はコマンドプロンプトに対応していないのだろうか」と思いつついろいろ試していたところ、なんということでしょう。tasklist を実行した瞬間にウィンドウタイトル「MyTitle」の後ろに現在実行中のコマンド「tasklist /FI “WINDOWTITLE eq MyTitle”」が付加されているではありませんか(※ tasklist と /FI の間のスペースはなぜか 2 個あります)。
【検索前】
【検索中】
【検索後】
そこで、「MyTitle」ではなく、検索中に一瞬表示される「MyTitle – tasklist /FI “WINDOWTITLE eq MyTitle”」を検索対象にしてみました。
C:\>tasklist /FI "WINDOWTITLE eq MyTitle - tasklist /FI \"WINDOWTITLE eq MyTitle\""
すると、なんということでしょう。今度は「MyTitle」の後ろにさらに長くなった「tasklist /FI “WINDOWTITLE eq MyTitle – tasklist /FI \”WINDOWTITLE eq MyTitle\””」が付加されているではありませんか。
【検索前】
【検索中】
【検索後】
これではきりがありません。
ワイルドカードで検索
さらに調べたところ、tasklist のヘルプには明記されていませんが、検索対象にワイルドカードが使えることが分かりました。そこで、「MyTitle から始まる文字列」を意味する「MyTitle*」を指定すると、自分自身の情報が表示されました。
C:\>tasklist /FI "WINDOWTITLE eq MyTitle*"
イメージ名 PID セッション名 セッション# メモリ使用量
========================= ======== ================ =========== ============
cmd.exe 11428 Console 1 3,916 K
ヘッダが邪魔なので、「/NH」オプションをつけて消します。
C:\>tasklist /FI "WINDOWTITLE eq MyTitle*" /NH
cmd.exe 11428 Console 1 3,916 K
PID のみが欲しいので、for コマンドの中で実行し、左から 2 番目の値のみを抜き出し、環境変数 MyPid にセットします。
C:\>for /F "tokens=2" %i in ('tasklist /FI "WINDOWTITLE eq MyTitle*" /NH') do set MyPid=%i
以上で、コマンドプロンプトから自分自身の PID を取得し、環境変数 MyPid にセットできました。
取得した PID は、ログに出力したり、
C:\>echo Start %MyPid% >> %temp%\MyLog.txt
C:\>type %temp%\MyLog.txt
Start 11428
ウィンドウタイトルに設定したりできます。
C:\>title %comspec% [%MyPid%]
なお、PID を取得する方法として「tasklist /v | find “MyTitle”」も考えられますが、こちらは動作が遅いようです。