Python子进程与Powershell和Pipeline Operators通信

wwwo4jvm  于 2023-10-18  发布在  Shell
关注(0)|答案(2)|浏览(104)

我希望找到我的Windows电脑上的所有Chrome示例的启动时间。在powershell中,我可以通过get-process chrome | Format-Table StartTime来实现。
我想在一个python脚本中这样做,并使用它的输出。我的代码如下:

import subprocess
call = "powershell get-process chrome | powershell Format-Table ProcessName, StartTime"
process = subprocess.Popen(call, stdout=subprocess.PIPE, stderr=None, shell=True)
outputs = process.communicate()
print(outputs)

此命令的输出是[''],即使打开了Chrome。

观察结果

如果将call更改为

call = "powershell get-process chrome"

这将如预期的那样输出表格。我认为这个错误与管道操作员有关。

jhdbpxl9

jhdbpxl91#

Your own helpful answer是解决问题的最快方法,基于您通过cmd.exe * 隐式调用 * 的方法,由于shell=True^-转义|可以保护它免受cmd.exe * 的预先解释
正如链接的答案所暗示的,不要使用powershell * 两次 :传递一个 single command,它是一个 PowerShell pipeline,传递给powershell.exe,Windows PowerShell CLI,这意味着使用-Command-c)参数。
虽然
shell=True在语法上很方便 ,(将整个命令行作为 * 单个字符串 * 提供),它不是 * 必要的 *,并且由于必须创建额外的cmd.exe进程而导致开销*-更不用说需要 * 小心转义 ,以防止cmd.exe对命令行的某些部分进行不必要的预先解释,就像眼前的情况一样。
因此,考虑直接调用powershell.exe
,在这种情况下,不需要 * 对|进行转义,但最好
将命令作为 * 数组**传递,其第一个元素是目标 * 可执行文件 *,其后续元素是参数,单独指定:[2]

# ...
# Construct the PowerShell CLI call as an *array*:
# The target executable, followed by the arguments to pass to it.
call = "powershell.exe", "-c", "Get-Process chrome | Format-Table ProcessName, StartTime"

# Make the call, but do NOT use `shell=True`
process = subprocess.Popen(call, stdout=subprocess.PIPE, stderr=None)
# ...

顺便说一句:

  • 上述应用类似地适用于高级subprocess.run()函数,除了高级用例(如 * 异步 * 执行和 * 动态 * 提供stdin输入),以响应运行进程的输出之外,它比它所基于的低级subprocess.Popen接口更可取。

[1]请注意,相比之下,pwsh,PowerShell(核心)CLI,现在 * 需要 * 使用-Command/-c
[2]在 Windows 上,您 * 仍然可以 * 传递一个字符串,即整个命令行(仅使用"..."作为 * 嵌入式 * 引号),但在类似 Unix 的平台上,为了传递参数,必须使用数组。(但是,在 argument-less 调用中,可执行文件的名称或路径可以作为字符串传递,而不是作为两个平台上的一个元素数组传递。此外,*with shell=True * 传递单个字符串(即使带有嵌入式参数)在两个平台上都有效,因为该字符串将成为传递给shell可执行文件的单个参数。

uinbv5nw

uinbv5nw2#

你需要转义管道操作符,它才能在子进程中与powershell很好地配合。将call更改为

call = "powershell get-process chrome ^| Format-Table ProcessName, StartTime"

解决问题。

相关问题