如何在脚本中获取进程ID

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在脚本中获取进程ID相关的知识,希望对你有一定的参考价值。

我想要知道运行中脚本子shell的进程id。我该如何在shell脚本中得到PID。

当我在执行shell脚本时,它会启动一个叫子shell的进程。作为主shell的子进程,子shell将shell脚本中的命令作为批处理运行(因此称为“批处理进程”)。

在某些情况下,你也许想要知道运行中的子shell的PID。这个PID信息可以在不同的情况下使用。比如,你可以使用shell脚本的PID在/tmp下创建一个唯一的临时文件。有时侯脚本需要检测所有运行的进程,它可以从进程列表中排除自身的子shell。

在bash中,子shell进程的PID存储在一个特殊的变量‘$$’中。这个变量只读,你不可以在脚本中修改它。比如:
#!/bin/bash
echo "PID of this script: $$"

上面的脚本会得到下面的输出:
PID of this script: 6583
除了$$, bash shell还会导出其他的只读变量。比如,PPID存储子shell父进程的ID(也就是主shell)。UID存储了执行这个脚本的当前用户ID。比如:
#!/bin/bash
echo "PID of this script: $$"
echo "PPID of this script: $PPID"
echo "UID of this script: $UID"

输出是:
PID of this script: 6686
PPID of this script: 4656
UID of this script: 1000
上面输出中,PID每次执行都会变化。这个因为每次运行都会创建一个新的shell。另一方面,PPID每次都会一样只要你在同一个shell中运行。

对于所有bash内置变量列表,参考man页。
$ man bash
参考技术A 在某些情况下,你也许想要知道运行中的子shell的PID。这个PID信息可以在不同的情况下使用。比如,你可以使用shell脚本的PID在/tmp下创建一个唯一的临时文件。有时侯脚本需要检测所有运行的进程,它可以从进程列表中排除自身的子shell。

在bash中,子shell进程的PID存储在一个特殊的变量‘$$’中。这个变量只读,你不可以在脚本中修改它。比如:
#!/bin/bash
echo "PID of this script: $$"

上面的脚本会得到下面的输出:
PID of this script: 6583
除了$$, bash shell还会导出其他的只读变量。比如,PPID存储子shell父进程的ID(也就是主shell)。UID存储了执行这个脚本的当前用户ID。比如:
#!/bin/bash
echo "PID of this script: $$"
echo "PPID of this script: $PPID"
echo "UID of this script: $UID"

输出是:
PID of this script: 6686
PPID of this script: 4656
UID of this script: 1000
上面输出中,PID每次执行都会变化。这个因为每次运行都会创建一个新的shell。另一方面,PPID每次都会一样只要你在同一个shell中运行。

对于所有bash内置变量列表,参考man页。
$ man bash

如何使用脚本通过其服务名称获取进程ID到变量

【中文标题】如何使用脚本通过其服务名称获取进程ID到变量【英文标题】:How to get process id by its service name with a script to variable 【发布时间】:2014-12-07 11:57:21 【问题描述】:

我有一个名为 WinDefend 的服务,它在进程 svchost.exe 上运行 还有其他许多 svchost.exe 进程,我需要找到一种方法来获取它的 ID。 当我运行tasklist /svc 时,我可以看到:

我不确定如何获得它。 我找到了这个命令,但是当我尝试select "PID" 时,它给了我一个空列。

我需要把进程的PID变成变量。

【问题讨论】:

【参考方案1】:

tasklist 只是返回文本,而不是具有您可以访问的属性的实际对象。您可以改用 WMI 来获取此信息:

$id = Get-WmiObject -Class Win32_Service -Filter "Name LIKE 'WinDefend'" | 
      Select-Object -ExpandProperty ProcessId

$process = Get-Process -Id $id

PowerShell Core 更新

在版本 6 中,Windows PowerShell 开始通过基于 .NET Core 的 PowerShell Core 实现跨平台支持。这导致 cmdlet 发生了许多以 Windows 为中心的更改,有些更改被完全排除在外。 WMI 是一种仅限 Windows 的技术,因此它的 cmdlet(例如 Get-WmiObject)没有被移植。但是,它的功能可通过 CIM cmdlet(例如 Get-CimInstance)获得,这是一个适用于 PowerShell 6+ 的版本:

$id = Get-CimInstance -Class Win32_Service -Filter "Name LIKE 'WinDefend'" | 
      Select-Object -ExpandProperty ProcessId

$process = Get-Process -Id $id

【讨论】:

我很抱歉这个非常愚蠢的问题,但我在哪里执行这个? @RaulChiarella 在 powershell 中? :) 我不太清楚你的意思,但是现在以 powershell 核心为标准,我已经进行了更新,应该适用于该版本。【参考方案2】:
$p=Tasklist /svc /fi "SERVICES eq windefend" /fo csv | convertfrom-csv
$p.PID

【讨论】:

【参考方案3】:

这很烦人,如果你想要当前进程的 pid,它需要你为你的脚本设置一个唯一的标题。然后在进程列表中搜索该唯一标题。值得庆幸的是,标题命令允许您这样做。另见 MagicAndi 的 response...

这是我的批处理文件解决方案:

@ECHO OFF
:SetVars
    SET _Thread=%1
    title=ExecBatch_%_Thread%
    Set /A "_iPID=0"
:Main
    CALL :getPID _iPID %_Thread%
    ...
EXIT /b

::----------------
::---- GetPID ---- 
::----------------
:getPID 
    setlocal   
        set _getPIDcmd=tasklist /v /fo csv 
        for /f "tokens=2 delims=," %%i in ('%_getPIDcmd% ^| findstr /i "ExecBatch_%2"') do (
            echo %%~i
            set _pid=%%~i
        )
    endlocal & Set %~1=%_pid%
exit /b

顺便说一句,这些年来我一直“很高兴”通过 API、批处理或 ps 一次又一次地这样做。选择你的毒药 - 在 Windows 平台上都是一样的。

我通过 powershell 找到了一个更好的方法:$pid 返回当前进程的进程 id。

【讨论】:

我认为你误解了这个问题很多。【参考方案4】:
# Enter servicename. (instead of 'netman')
$service = Get-CimInstance -class win32_service | Where-Object name -eq 'netman' | select name, processid
$process = Get-Process | Where-Object ID -EQ $service.processid
Clear-Host
Write-Host '********* ServiceName, PID and ProcessName ******'
Write-Host 'ServiceName:' $service.name 
Write-Host 'ID:' $process.Id 
Write-Host 'ProcessName:' $process.Name

谢谢,

【讨论】:

虽然这个答案可能会解决这个问题,但如果你解释它是如何工作的会更有用【参考方案5】:

另一种获取进程PID的方法:

$serviceName = 'svchost.exe'
$pidArgumentPlacement = 1

# Call for the verbose version of tasklist and filter it for the line with your service's name. 
$serviceAsCSVString = tasklist /v /fo csv | findstr /i $serviceName

# Remove the quotes from the CSV string
$serviceCSVStringWithoutQuotes = $serviceAsCSVString -replace '["]'
# Turn the string into an array by cutting at the comma
$serviceAsArray = $serviceCSVStringWithoutQuotes -split ","
# Get the pid from the array
$servicePID = $serviceAsArray[$pidArgumentPlacement]

或者你可以总结为:

$servicePID = $($($(tasklist /v /fo csv | findstr /i $serviceName) -replace '["]') -split ",")[$pidArgumentPlacement]

注意:这将获取与您的$serviceName 匹配的第一个服务,如果您运行一个运行多个自身实例的服务(例如 slack),您将只得到第一个pid。 tasklist /v /fi "IMAGENAME eq slack.exe" /fo csv 将返回一个数组,每个 CSV 行都是一个数组条目。您也可以使用findstr 过滤它以避免获取列名。

编辑: 由于 WinDefend 是程序的子服务(在本例中为 svchost.exe),您可能需要将 tasklist 的详细标志交换为 /svc,如下所示:

$serviceAsCSVString = tasklist /svc /fo csv | findstr /i $serviceName

或者通过过滤器搜索服务的名称:

$serviceAsCSVString = tasklist /svc /fi "SERVICES eq $serviceName" /fo csv | findstr /i $serviceName

并考虑到过滤器返回一行列名以及您要查找的行:

$serviceCSVStringWithoutQuotes = $serviceAsCSVString[1] -replace '["]'

假设您已将 $serviceName 更改为 WinDefend 而不是 svchost.exe

【讨论】:

当我运行 $servicename = 'WinDefend' $pidArgumentPlacement = 1 # Call for the verbose version of tasklist and filter it for the line with your service's name. $serviceAsCSVString = tasklist /v /fo csv | findstr /i $serviceName 时,$serviceAsCSVString 是空的。 抱歉,我的脚本中有错字; $serviceName 在第一行拼写错误。再试一次,确保变量名匹配; powershell 区分大小写。 它不起作用,Powershell 不区分大小写。如果您将运行$a = "a"; $A,您将看到它将打印相同的值。你在你的机器上检查过这个代码吗?运行:$serviceName = 'WinDefend' $pidArgumentPlacement = 1 tasklist /v /fo csv | findstr /i $serviceName 它不会找到任何东西。问题是因为您没有使用显示服务名称的/svc 开关。因此它不显示WinDefend 服务。修复您的代码:只需将 /v 替换为 /svc 顺便说一句,svchost.exe 不是一个好例子,因为它不是服务。 我已经更新了我的答案,似乎我误解了你在寻找什么。【参考方案6】:
Get-Process -Id ((Get-WmiObject -Class Win32_Service -Filter "Name -eq 'WinDefend'").ProcessId)

【讨论】:

虽然此代码可能会回答问题,但提供有关 why 和/或 如何 此代码回答问题的附加上下文可提高其长期价值.【参考方案7】:

答案很简单。 (gps -id (get-wmiobject -query "select * from win32_service where name='servicename'").processid).priority class="priority"

执行该命令,它会设置指定的服务,即使它在 svchost 中。

已编辑:您只是在寻找 PID。只需执行相同的命令减去优先级设置即可。我假设您将使用它来设置优先级。呵呵

【讨论】:

【参考方案8】:

我用过这个,效果很好。 YMMV

$ProcessName = "SomeProcessName"

$pidnumber = Get-Process -Name $ProcessName | Select -expand ID

【讨论】:

但我的情况不同。进程名称是svchost.exe,它在任务管理器中出现了几次。然后,你只需要找到与WinDefend服务相关的那个”,仅仅显示所有svchost.exe的ID是不行的 我正在尝试在服务上执行此操作,我似乎无法将 -expand id 与 get-service 一起使用。

以上是关于如何在脚本中获取进程ID的主要内容,如果未能解决你的问题,请参考以下文章

如何获取后台进程的进程ID?

如何使用脚本通过其服务名称获取进程ID到变量

如何在python中获取名称的进程ID

如何在linux中使用shell脚本杀死进程时获取退出代码=0

linux在shell脚本中获取进程ID,父进程ID和用户ID的方法

Java如何得到当前进程ID号