【问题标题】:Getting Pid of cmd while running batch script运行批处理脚本时获取 cmd 的 Pid
【发布时间】:2015-03-04 18:21:40
【问题描述】:

这应该很简单,但我没找到。

如果我在 cmd 中运行一些批处理脚本,我如何获取托管 cmd 的进程 ID?

set currentCmdPid= /* some magic */
echo %currentCmdPid%

我找到了很多使用tasklist 和名称过滤的解决方案,但我相信这对我不起作用,因为可以启动许多 cmd 实例。

再次,我想要一些简单优雅且防弹的解决方案。

谢谢。

【问题讨论】:

  • 嗯,这并不简单,但我还是认为it is bullet-proof
  • 为什么这在 Windwos 上这么难 :( 这是一件如此简单和常见的事情。
  • 如果 cmd 环境通过环境变量暴露给它自己的进程信息会很好,不是吗?无论如何,您获取当前控制台的 PID 的目的是什么?如果您将其用于进程锁定,there are probably better solutions for that.
  • 使用dbenham's solution 查找cmd.exe 的PID。它比 npocmaka 或我的更快。 npocmaka 仍然因为将我指向 dbenham's 而获得 +1。 :) 如果您想捕获正在启动的进程的 PID,而不是 cmd 本身的 PID,see this page
  • 最简单的解决方案是 call :spawn wrapper.bat 并将 wrapper.bat 的内容设置为 @app.exe >path\to\log.txt。或者你可以硬编码wmic process call create "%args:"=\"% >path\\to\\log.txt"。无论哪种方式,您都必须完全限定c:\path\to\log.txt。我认为wmic process call create 使用%systemroot%\system32 作为其工作目录。我不确定如何将> 作为call 参数的一部分而不引用它,所以我无法建议您如何将重定向包含在与call 相同的行中。用插入符号转义 > 似乎对我的测试没有任何影响。

标签: batch-file process cmd echo


【解决方案1】:

这是由same DosTips discussion and collaborative effort that npocmaka referenced 产生的my pure batch script version

@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

npocmaka's solution 将一个 exe 文件(已编译的 JScript)安装在与批处理脚本相同的文件夹中。

在我的机器上,我的纯批处理 getPID 运行速度比 npocmaka 的 exe 快 20%!这是因为 exe 首先确定自己的进程 PID,这需要很长时间,然后才能使用 WMI 确定所需的父 PID。我的脚本会生成一个唯一 ID(快得多),该 ID 会合并到 WMIC 调用中,以确定所需的父 PID。

在这两种解决方案中,大部分时间都花在 WMI 中,用于确定特定进程的父 PID。

【讨论】:

    【解决方案2】:

    这里的话题已经讨论过了->http://www.dostips.com/forum/viewtopic.php?p=38870

    这是我的解决方案:

    @if (@X)==(@Y) @end /* JScript comment
    @echo off
    setlocal
    
    for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
       set "jsc=%%v"
    )
    
    
    if not exist "%~n0.exe" (
       "%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0" 
    )
    
    %~n0.exe
    
    endlocal & exit /b %errorlevel%
    
    */
    
    
    import  System;
    import  System.Diagnostics;
    import  System.ComponentModel;
    import  System.Management;
    
    var myId = Process.GetCurrentProcess().Id;
    var query = String.Format("SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = {0}", myId);
    var search = new ManagementObjectSearcher("root\\CIMV2", query);
    var results = search.Get().GetEnumerator();
    if (!results.MoveNext()) {
       Console.WriteLine("Error");
       Environment.Exit(-1);
    }
    var queryObj = results.Current;
    var parentId = queryObj["ParentProcessId"];
    var parent = Process.GetProcessById(parentId);
    Console.WriteLine(parent.Id);
    

    【讨论】:

    • 请引用参考链接中答案的基本部分,因为如果链接页面发生变化,答案可能会失效。
    【解决方案3】:

    要获取 cmd PID,我从 cmd 运行 powershell 并获取父进程 ID——这将是 cmd PID。脚本获取父级的父级(因为FOR /F 调用另一个 cmd.exe)。

    FOR /F "tokens=* USEBACKQ" %%F IN (`powershell  -c "(gwmi win32_process | ? processid -eq ((gwmi win32_process | ? processid -eq  $PID).parentprocessid)).parentprocessid"`) DO (
      SET PCT_CleanAfterPID=%%F
    )
    
    ECHO %PCT_CleanAfterPID%
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-09
      • 2022-11-28
      • 1970-01-01
      • 2021-05-30
      • 1970-01-01
      • 2011-06-15
      • 2018-12-07
      • 1970-01-01
      相关资源
      最近更新 更多