【问题标题】:Python - pipelining subprocess in WindowsPython - Windows 中的流水线子进程
【发布时间】:2011-09-14 08:58:37
【问题描述】:

我使用的是 Windows 7,我已经在 Python 2.6.6 和 Python 3.2 下尝试过。

所以我试图从 Python 调用这个命令行:

netstat -ano | find ":80"

在 Windows cmd 下,此行运行良好。

所以,

  • 第一次尝试:

    output = subprocess.Popen(
               [r'netstat -ano | find ":80"'],
               stdout=subprocess.PIPE,
               shell=True
    ).communicate()
    

    “find”实际上没有收到正确的参数会引发错误(例如“find ":80" \'):

    Access denied - \
    
  • 第二次尝试:

    #calling netstat
    cmd_netstat = subprocess.Popen(
                    ['netstat','-ano'],
                    stdout = subprocess.PIPE
    )
    
    #pipelining netstat result into find
    cmd_find = subprocess.Popen(
                 ['find','":80"'],
                 stdin = cmd_netstat.stdout,
                 stdout = subprocess.PIPE
    )
    

    再次出现同样的错误。

    Access denied - \
    

我做错了什么? :(

编辑:

  • 第三次尝试(正如@Pavel Repin 建议的那样):

    cmd_netstat = subprocess.Popen(
                    ['cmd.exe', '-c', 'netstat -ano | find ":80"'],
                    stdout=subprocess.PIPE
    ).communicate()
    

    不幸的是,带有 ['cmd.exe','-c'] 的子进程会导致类似于死锁或空白 cmd 窗口的情况。我假设 cmd 忽略了“-c”,导致communicate() 无限期地等待 cmd 终止。由于这是 Windows,我敢打赌 cmd 只接受以斜杠 (/) 开头的参数。所以我用'/c'替换了'-c':

    cmd_netstat = subprocess.Popen(
                    ['cmd.exe', '/c', 'netstat -ano | find ":80"'],
                    stdout=subprocess.PIPE
    ).communicate()
    

    然后...回到同样的错误:

    Access denied - \
    

编辑: 我放弃了,我将在 Python 中处理 'netstat -ano' 返回的字符串。这可能是一个错误吗?

【问题讨论】:

  • 在尝试 N1 中,也许这可能有效:['cmd.exe', '-c', 'netstat -ano | find ":80"'] 作为 args 数组。在这种情况下,还要删除shell=True
  • @PavelRepin 刚刚在 Python 2.6.6 和 Python 3.2 中尝试过。不幸的是,带有 ['cmd.exe','-c'] 的子进程会导致类似于死锁或空白 cmd 窗口的情况...
  • (已删除,移至尝试 3)
  • 对不起@madeOfMeat,-c 是我的脑残。尝试/c 是对的,尽管很遗憾它仍然没有帮助。

标签: python subprocess


【解决方案1】:

我建议你在 Python 代码中做到最大。因此,您可以执行以下命令:

# executing the command
import subprocess
output = subprocess.Popen(['netstat', '-ano'], stdout=subprocess.PIPE).communicate()

然后通过解析输出:

# filtering the output
valid_lines = [ line for line in output[0].split('\r\n') if ':80' in line ]

你会得到一个行列表。在我的电脑上,端口号 1900 的输出如下所示(没有激活 html 连接):

['  UDP    127.0.0.1:1900         *:*                                    1388', '  UDP    192.xxx.xxx.233:1900    *:*                                    1388']

在我看来,这更容易使用。

请注意:

  • option shell=True 不是强制性的,但命令行窗口可以快速打开-关闭。看看什么最适合你,但要注意命令注入;
  • Popen 参数列表应为字符串列表。不需要引用列表部分,子流程会为您处理。

希望这会有所帮助。

编辑:哎呀,我错过了编辑的最后一行。看来你自己已经有了这个想法。

【讨论】:

    【解决方案2】:

    于是我重新审视了这个问题,找到了两个解决方案(我前段时间切换到Python 2.7,所以我不确定Python 2.6,但应该是一样的。):

    1. find 替换为 findstr,并删除双引号

      output = subprocess.Popen(['netstat','-ano','|','findstr',':80'],
                                stdout=subprocess.PIPE,
                                shell=True)
                         .communicate()
      

      但这并不能解释为什么不能使用“find”,所以:

    2. 使用字符串参数代替列表

      output = subprocess.Popen('netstat -ano | find ":80"',
                                stdout=subprocess.PIPE,
                                shell=True)
                         .communicate()
      

      pipeout = subprocess.Popen(['netstat', '-ano'], 
                                 stdout = subprocess.PIPE)
      output = subprocess.Popen('find ":80"', 
                                stdin = pipeout.stdout, 
                                stdout = subprocess.PIPE)
                         .communicate()
      

    问题在于:['find','":80"'] 实际上被翻译成 ['find,'\":80\"']。 因此在 Windows 命令 shell 中执行以下命令:

    >find \":80\"
    Access denied - \
    

    证明:

    • 跑步:

      output = subprocess.Popen(['echo','find','":80"'],
                                stdout=subprocess.PIPE,
                                shell=True)
                         .communicate()
      print output[0]
      

      返回:

      find \":80\"
      
    • 跑步:

      output = subprocess.Popen('echo find ":80"',
                                stdout=subprocess.PIPE,
                                shell=True)
                         .communicate()
      print output[0]
      

      返回:

      find ":80"
      

    【讨论】:

    • 为什么不.Popen(['find', ':80'], ...)
    【解决方案3】:

    新答案,再次阅读这个老问题后:这可能是由于以下两个事实:

    不确定这种“冲突”是一种错误,还是一种设计选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-14
      • 1970-01-01
      • 2011-12-13
      • 1970-01-01
      • 1970-01-01
      • 2011-10-17
      • 1970-01-01
      • 2015-11-10
      相关资源
      最近更新 更多