PowerShell 在 Linux 和 OSX 中获取进程的命令行参数
PowerShell get Command Line Args of Processes in Linux and OSX
在 PowerShell 中,使用 Get-WmiObject win32_process
可以获得 windows (like this) 中任何活动进程的命令行参数。你如何在 Linux and/or OSX 中做同样的事情?
ps
命令确实可以做到这一点,但我正在寻找 PowerShell 原生解决方案,以便能够保持强类型。
注意:从 PowerShell Core 7.1.0-rc.2 开始,new-for-7.1 .CommandLine
ETS 脚本 属性 存在,用于确定 [=139= 上的命令行] 和 在 Linux 上。
然而:
- 在撰写本文时未提供针对 macOS 的解决方案,GitHub feature request #13943 旨在更正。
- Linux 解决方案的行为有些出乎意料,如 GitHub issue #13944 中所讨论 - 下面的解决方案解决了这个问题,尽管代价是参数边界丢失。
底部详述的解决方案适用于 macOS(至少也适用于某些 Linux 发行版),并且可以轻松集成到 .CommandLine
属性 中,如下所示 -您甚至可以在早期的 PowerShell [Core] 版本中执行此操作,甚至可以在 Windows PowerShell:
中执行此操作
# Run this once per session to add a / update the .CommandLine property
# on System.Diagnostics.Process to report the process' command line
# on Windows, Linux, and macOS
Update-TypeData -Force -Value {
if ($env:OS -eq 'Windows_NT') {
(Get-CimInstance Win32_Process -Filter "ProcessId = $($this.Id)").CommandLine
} elseif ($IsLinux) {
(Get-Content -LiteralPath "/proc/$($this.Id)/cmdline") -replace "`0", ' '
} elseif ($IsMacOs) {
ps -o command= $this.Id
}
} -TypeName System.Diagnostics.Process -MemberName CommandLine -MemberType ScriptProperty
启用后,您可以按如下方式使用它:
$pidOfInterest = $PID # use the PowerShell session's own as an example
(Get-Process -Id $pidOfInterest).CommandLine
注:
与 Windows 不同,在 Unix 平台上,报告的命令行 不是 原始命令行的忠实表示;值得注意的是,最初由单或 double-quoting 强制执行的参数边界丢失了:
注意:在 Unix-like 平台上,进程不会收到它们自己必须解析的 命令行 (不幸的是 Windows);相反,他们收到 array of verbatim arguments。因此,没有这样的原始命令行,只有传递给原始 shell 的 shell-specific 命令行,然后将其转换为数组在创建过程中逐字传递参数。
在 macOS 上,下面详述的基于 ps
的解决方案提供了 no 关于原始参数边界的信息,并简单地将逐字参数与空格连接起来,因此生成的 command-line 字符串通常不能像原始调用那样工作。
在 Linux 上,特殊 /proc/<pid>/cmdline
文件 do 保留原始参数边界,只需使用 NUL
字符(0x0
)而不是空格来加入逐字的参数;然而,从中重建一个可用的命令行需要付出不小的努力(特别是需要重新创建必要的引用和转义),甚至这也提出了概念上的挑战:what shell 你是否重建命令行,例如,考虑到 PowerShell 的语法不同于 Bash 的语法?因此,上面的命令也只是将 Linux 上的逐字参数与空格连接起来,就像 ps
在 macOS 上所做的一样。
访问 .CommandLine
属性 在性能方面代价高昂,因为它调用 CIM/WMI 对 Windows 的调用,并且 运行 Unix 子进程中的外部可执行文件。
在macOS上,可以使用标准的ps
utility[1]如下,但是要注意命令行它 returns 缺少原始引用:
# Print the command line used to invoke this PowerShell session,
# represented by automatic variable $PID.
# Note that $PID is just an *example* PID (process identifier).
ps -o command= $PID
注意:command
是 args
字段名称的 非标准 变体,不受后者 64 个字符的限制。 Linux 和 macOS 都支持它。
为了说明引用问题:
以下命令(从 PowerShell 执行):
pwsh -noprofile -noexit -c "'hi there'; ps -o command= `$PID"
输出一个字符串如:
/usr/local/bin/pwsh -noprofile -noexit -c 'hi there'; ps -o command= $PID
请注意包含原始 -c
参数的 "..."
引号是如何丢失的。
[1] 高级 Linux-specific 替代方案是 Get-Content -LiteralPath /proc/$PID/cmdline
,它具有用 NUL
字符分隔参数的优点是为了保留原始参数边界 - 但要查看这些边界需要额外的工作。 ps
解决方案也适用于至少一些 Linux 发行版,但可以想象有 ps
正在使用的实现不支持 command
字段。无论哪种方式,ps
解决方案都缺少有关原始参数边界的信息。
在 PowerShell 中,使用 Get-WmiObject win32_process
可以获得 windows (like this) 中任何活动进程的命令行参数。你如何在 Linux and/or OSX 中做同样的事情?
ps
命令确实可以做到这一点,但我正在寻找 PowerShell 原生解决方案,以便能够保持强类型。
注意:从 PowerShell Core 7.1.0-rc.2 开始,new-for-7.1 .CommandLine
ETS 脚本 属性 存在,用于确定 [=139= 上的命令行] 和 在 Linux 上。
然而:
- 在撰写本文时未提供针对 macOS 的解决方案,GitHub feature request #13943 旨在更正。
- Linux 解决方案的行为有些出乎意料,如 GitHub issue #13944 中所讨论 - 下面的解决方案解决了这个问题,尽管代价是参数边界丢失。
底部详述的解决方案适用于 macOS(至少也适用于某些 Linux 发行版),并且可以轻松集成到 .CommandLine
属性 中,如下所示 -您甚至可以在早期的 PowerShell [Core] 版本中执行此操作,甚至可以在 Windows PowerShell:
# Run this once per session to add a / update the .CommandLine property
# on System.Diagnostics.Process to report the process' command line
# on Windows, Linux, and macOS
Update-TypeData -Force -Value {
if ($env:OS -eq 'Windows_NT') {
(Get-CimInstance Win32_Process -Filter "ProcessId = $($this.Id)").CommandLine
} elseif ($IsLinux) {
(Get-Content -LiteralPath "/proc/$($this.Id)/cmdline") -replace "`0", ' '
} elseif ($IsMacOs) {
ps -o command= $this.Id
}
} -TypeName System.Diagnostics.Process -MemberName CommandLine -MemberType ScriptProperty
启用后,您可以按如下方式使用它:
$pidOfInterest = $PID # use the PowerShell session's own as an example
(Get-Process -Id $pidOfInterest).CommandLine
注:
与 Windows 不同,在 Unix 平台上,报告的命令行 不是 原始命令行的忠实表示;值得注意的是,最初由单或 double-quoting 强制执行的参数边界丢失了:
注意:在 Unix-like 平台上,进程不会收到它们自己必须解析的 命令行 (不幸的是 Windows);相反,他们收到 array of verbatim arguments。因此,没有这样的原始命令行,只有传递给原始 shell 的 shell-specific 命令行,然后将其转换为数组在创建过程中逐字传递参数。
在 macOS 上,下面详述的基于
ps
的解决方案提供了 no 关于原始参数边界的信息,并简单地将逐字参数与空格连接起来,因此生成的 command-line 字符串通常不能像原始调用那样工作。在 Linux 上,特殊
/proc/<pid>/cmdline
文件 do 保留原始参数边界,只需使用NUL
字符(0x0
)而不是空格来加入逐字的参数;然而,从中重建一个可用的命令行需要付出不小的努力(特别是需要重新创建必要的引用和转义),甚至这也提出了概念上的挑战:what shell 你是否重建命令行,例如,考虑到 PowerShell 的语法不同于 Bash 的语法?因此,上面的命令也只是将 Linux 上的逐字参数与空格连接起来,就像ps
在 macOS 上所做的一样。
访问
.CommandLine
属性 在性能方面代价高昂,因为它调用 CIM/WMI 对 Windows 的调用,并且 运行 Unix 子进程中的外部可执行文件。
在macOS上,可以使用标准的ps
utility[1]如下,但是要注意命令行它 returns 缺少原始引用:
# Print the command line used to invoke this PowerShell session,
# represented by automatic variable $PID.
# Note that $PID is just an *example* PID (process identifier).
ps -o command= $PID
注意:command
是 args
字段名称的 非标准 变体,不受后者 64 个字符的限制。 Linux 和 macOS 都支持它。
为了说明引用问题:
以下命令(从 PowerShell 执行):
pwsh -noprofile -noexit -c "'hi there'; ps -o command= `$PID"
输出一个字符串如:
/usr/local/bin/pwsh -noprofile -noexit -c 'hi there'; ps -o command= $PID
请注意包含原始 -c
参数的 "..."
引号是如何丢失的。
[1] 高级 Linux-specific 替代方案是 Get-Content -LiteralPath /proc/$PID/cmdline
,它具有用 NUL
字符分隔参数的优点是为了保留原始参数边界 - 但要查看这些边界需要额外的工作。 ps
解决方案也适用于至少一些 Linux 发行版,但可以想象有 ps
正在使用的实现不支持 command
字段。无论哪种方式,ps
解决方案都缺少有关原始参数边界的信息。