【问题标题】:Python 3.10 script calling a Powershell script - How to store output after a certain string调用 Powershell 脚本的 Python 3.10 脚本 - 如何在某个字符串之后存储输出
【发布时间】:2022-10-06 07:43:37
【问题描述】:

我希望有人可以帮助我解决这个问题,因为我迷路了。 我正在调用一个产生多行输出的 Powershell 脚本,这在摘录中:

7-Zip 22.01 (x64) : Copyright (c) 1999-2022 Igor Pavlov : 2022-07-15

Scanning the drive:
7 folders, 21 files, 21544 bytes (22 KiB)

Creating archive: conf.tar
Creating archive: conf2.tar

Removing tar file after upload...
Generating Links:
--------------------------------------------------------------
Link_1
https://some-repository.s3.ap-northeast-2.amazonaws.com/test/conf.tar?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXXXXXXXXXXXXXXX..
--------------------------------------------------------------
Link_2
https://some-repository.s3.ap-northeast-2.amazonaws.com/test/conf2.tar?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXXXXXXXXXXXXXXX..

我的 Python 脚本以这种方式调用 Powershell 脚本:

import subprocess, sys
p = subprocess.Popen([\"powershell.exe\", 
              \"script.ps1\"], 
              stdout=sys.stdout, shell=True)              
p_out, p_err = p.communicate()
print(p_out)

当我从 Powershell CLI 运行 python 脚本时,我可以在屏幕上看到输出。 有没有办法从输出中提取这些链接并将它们传递给 Python?

  • 您应该将p_out 中的所有内容都作为字符串(因此您已经在 Python 中拥有它),现在您应该使用 Python\ 的函数从该字符串中提取它。您可以在开头使用https 拆分为行和搜索行。或者你可以使用正则表达式。
  • @furas,问题是stdout=sys.stdout(而不是stdout=subprocess.PIPE),它阻止p_out 接收任何输出。

标签: python powershell


【解决方案1】:
  • 为了捕获stdout 和 stderr 输出,您必须将 stdout=sys.stdout 替换为 stdout=PIPE, stderr=PIPE

    • 相比之下,stdout=sys.stdout 将 PowerShell 调用的输出直接传递到控制台(终端),因此p_outp_err 最终成为None
  • 在您的情况下,不需要shell=True(通过平台的默认外壳调用) - 它只会减慢速度。

  • 添加universal_newlines=True 使Python 自动将收集到的stdout 和stderr 输出报告为字符串;在 v3.7+ 中,您可以使用概念上更清晰的别名 text=True

  • 虽然您可以提取 Python 代码中感兴趣的行然后,您的 PowerShell 调用的一个小补充可以让您在源头上执行此操作。

所以:

import subprocess

p = subprocess.Popen(
  ['powershell', '-NoProfile', '-Command', "(./script.ps1) -match '^https://'" ], 
  stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
)

# Wait for the process to terminate and collect its stdout and stderr output.
p_out, p_err = p.communicate()

# Split the single multi-line string that contains the links
# into individual lines.
lines = p_out.splitlines()

print(lines)

笔记:

  • PowerShell CLI 使用的参数:

    • -NoProfile 不是绝对必要的,但可取的,因为它抑制了 PowerShell 的 profiles 的加载,这既可以提高性能,又可以提供可预测的执行环境。
    • -Command 对于powershell.exe 不是绝对必要的,Windows PowerShellCLI,因为它是隐含的默认值;然而,它如果您调用 PowerShell (Core) 7+ CLI、pwsh.exe(现在默认为 -File),则这是必需的。
  • 用于提取链接的 PowerShell 代码:

    • 由于您的脚本调用了外部程序, 7z.exe, 报告该程序的标准输出逐行通过 PowerShell。
    • 当基于正则表达式的-match 运算符被赋予一个大批作为其 LHS 操作数,它充当筛选.因此,仅返回那些以 (^) 字符串 https:// 开头的行。

【讨论】:

  • 谢谢,我已经对此进行了测试,并且我有一个包含链接的数组,这正是我所需要的!不幸的是,它没有记录我的赞成票,因为这是我的第一篇文章。
  • 很高兴听到它,@MBud(我只是稍微简化了解决方案 - 不需要from asyncio.subprocess import PIPE - suprocess.PIPE 就足够了)。虽然您确实需要至少 15 个声望点赞成票privilege, accepting 自己的问题的答案有最低声誉要求。
  • 是的,我确实接受了答案@mklement0
  • 嗨@mklement0 不幸的是我找不到这个问题的答案,所以我希望你能帮助我。在这种情况下,如何将参数传递给 powershell 脚本?我不明白如何继续使用正则表达式,但传递我存储的变量值。例如,使用product_Version= "1.1.7.2" 等python 变量,代码应执行script.ps1 1.1.7.2 -match '^https://'
  • @MBud,使用字符串插值,例如使用 f 字符串:f"{product_Version} -match '^https://'" 如果您需要进一步的帮助,请提出新问题。
【解决方案2】:

您应该将p_out 中的所有内容作为字符串(因此您应该已经在 Python 中拥有它),现在您应该使用 Python 的函数从该字符串中提取它。您可以在开头使用https 拆分为行和搜索行。或者你可以使用正则表达式。

p_out  = '''7-Zip 22.01 (x64) : Copyright (c) 1999-2022 Igor Pavlov : 2022-07-15

Scanning the drive:
7 folders, 21 files, 21544 bytes (22 KiB)

Creating archive: conf.tar
Creating archive: conf2.tar

Removing tar file after upload...
Generating Links:
--------------------------------------------------------------
Link_1
https://some-repository.s3.ap-northeast-2.amazonaws.com/test/conf.tar?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXXXXXXXXXXXXXXX..
--------------------------------------------------------------
Link_2
https://some-repository.s3.ap-northeast-2.amazonaws.com/test/conf2.tar?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXXXXXXXXXXXXXXX..'''

lines = p_out.split('\n')

links = []

for line in lines:
    if line.startswith('http'):
        line = line.strip() # remove '\n' and spaces
        links.append(line)
        
for url in links:        
    print('url:', url)

结果:

url: https://some-repository.s3.ap-northeast-2.amazonaws.com/test/conf.tar?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXXXXXXXXXXXXXXX..
url: https://some-repository.s3.ap-northeast-2.amazonaws.com/test/conf2.tar?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXXXXXXXXXXXXXXX..

如果您在p_out 中没有它,那么您应该检查p_err 是否存在。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-23
    • 1970-01-01
    • 2015-07-07
    • 1970-01-01
    相关资源
    最近更新 更多