用管道链接多个 Popen 命令

发布于 2024-12-04 02:13:55 字数 611 浏览 2 评论 0原文

我知道如何使用 cmd = subprocess.Popen 然后使用 subprocess.communicate 运行命令。 大多数时候,我使用 shlex.split 标记的字符串作为 Popen 的“argv”参数。 使用“ls -l”的示例:

import subprocess
import shlex
print subprocess.Popen(shlex.split(r'ls -l'), stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()[0]

但是,管道似乎不起作用...例如,以下示例返回注释:

import subprocess
import shlex
print subprocess.Popen(shlex.split(r'ls -l | sed "s/a/b/g"'), stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()[0]

您能告诉我我做错了什么吗?

谢谢

I know how to run a command using cmd = subprocess.Popen and then subprocess.communicate.
Most of the time I use a string tokenized with shlex.split as 'argv' argument for Popen.
Example with "ls -l":

import subprocess
import shlex
print subprocess.Popen(shlex.split(r'ls -l'), stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()[0]

However, pipes seem not to work... For instance, the following example returns noting:

import subprocess
import shlex
print subprocess.Popen(shlex.split(r'ls -l | sed "s/a/b/g"'), stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()[0]

Can you tell me what I am doing wrong please?

Thx

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

那请放手 2024-12-11 02:13:55

我认为您想在这里实例化两个单独的 Popen 对象,一个用于“ls”,另一个用于“sed”。您需要将第一个 Popen 对象的 stdout 属性作为 stdin 参数传递给第二个 Popen 对象。

示例:

p1 = subprocess.Popen('ls ...', stdout=subprocess.PIPE)
p2 = subprocess.Popen('sed ...', stdin=p1.stdout, stdout=subprocess.PIPE)
print p2.communicate()

如果您有更多命令,您可以继续以这种方式链接:

p3 = subprocess.Popen('prog', stdin=p2.stdout, ...)

请参阅子流程文档了解有关如何使用子流程的更多信息。

I think you want to instantiate two separate Popen objects here, one for 'ls' and the other for 'sed'. You'll want to pass the first Popen object's stdout attribute as the stdin argument to the 2nd Popen object.

Example:

p1 = subprocess.Popen('ls ...', stdout=subprocess.PIPE)
p2 = subprocess.Popen('sed ...', stdin=p1.stdout, stdout=subprocess.PIPE)
print p2.communicate()

You can keep chaining this way if you have more commands:

p3 = subprocess.Popen('prog', stdin=p2.stdout, ...)

See the subprocess documentation for more info on how to work with subprocesses.

怪我入戏太深 2024-12-11 02:13:55

我做了一个小功能来帮助管道,希望它有帮助。它将根据需要链接 Popens。

from subprocess import Popen, PIPE
import shlex

def run(cmd):
  """Runs the given command locally and returns the output, err and exit_code."""
  if "|" in cmd:    
    cmd_parts = cmd.split('|')
  else:
    cmd_parts = []
    cmd_parts.append(cmd)
  i = 0
  p = {}
  for cmd_part in cmd_parts:
    cmd_part = cmd_part.strip()
    if i == 0:
      p[i]=Popen(shlex.split(cmd_part),stdin=None, stdout=PIPE, stderr=PIPE)
    else:
      p[i]=Popen(shlex.split(cmd_part),stdin=p[i-1].stdout, stdout=PIPE, stderr=PIPE)
    i = i +1
  (output, err) = p[i-1].communicate()
  exit_code = p[0].wait()

  return str(output), str(err), exit_code

output, err, exit_code = run("ls -lha /var/log | grep syslog | grep gz")

if exit_code != 0:
  print "Output:"
  print output
  print "Error:"
  print err
  # Handle error here
else:
  # Be happy :D
  print output

I've made a little function to help with the piping, hope it helps. It will chain Popens as needed.

from subprocess import Popen, PIPE
import shlex

def run(cmd):
  """Runs the given command locally and returns the output, err and exit_code."""
  if "|" in cmd:    
    cmd_parts = cmd.split('|')
  else:
    cmd_parts = []
    cmd_parts.append(cmd)
  i = 0
  p = {}
  for cmd_part in cmd_parts:
    cmd_part = cmd_part.strip()
    if i == 0:
      p[i]=Popen(shlex.split(cmd_part),stdin=None, stdout=PIPE, stderr=PIPE)
    else:
      p[i]=Popen(shlex.split(cmd_part),stdin=p[i-1].stdout, stdout=PIPE, stderr=PIPE)
    i = i +1
  (output, err) = p[i-1].communicate()
  exit_code = p[0].wait()

  return str(output), str(err), exit_code

output, err, exit_code = run("ls -lha /var/log | grep syslog | grep gz")

if exit_code != 0:
  print "Output:"
  print output
  print "Error:"
  print err
  # Handle error here
else:
  # Be happy :D
  print output
墨洒年华 2024-12-11 02:13:55

shlex仅根据shell规则分割空格,但不处理管道。

然而,它应该这样工作:

import subprocess
import shlex

sp_ls = subprocess.Popen(shlex.split(r'ls -l'), stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
sp_sed = subprocess.Popen(shlex.split(r'sed "s/a/b/g"'), stdin = sp_ls.stdout, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
sp_ls.stdin.close() # makes it similiar to /dev/null
output = sp_ls.communicate()[0] # which makes you ignore any errors.
print output

根据 help(subprocess)'s

Replacing shell pipe line
-------------------------
output=`dmesg | grep hda`
==>
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

HTH

shlex only splits up spaces according to the shell rules, but does not deal with pipes.

It should, however, work this way:

import subprocess
import shlex

sp_ls = subprocess.Popen(shlex.split(r'ls -l'), stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
sp_sed = subprocess.Popen(shlex.split(r'sed "s/a/b/g"'), stdin = sp_ls.stdout, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
sp_ls.stdin.close() # makes it similiar to /dev/null
output = sp_ls.communicate()[0] # which makes you ignore any errors.
print output

according to help(subprocess)'s

Replacing shell pipe line
-------------------------
output=`dmesg | grep hda`
==>
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

HTH

嘿咻 2024-12-11 02:13:55
"""
Why don't you use shell

"""

def output_shell(line):

    try:
        shell_command = Popen(line, stdout=PIPE, stderr=PIPE, shell=True)
    except OSError:
        return None
    except ValueError:
        return None

    (output, err) = shell_command.communicate()
    shell_command.wait()
    if shell_command.returncode != 0:
        print "Shell command failed to execute"
        return None
    return str(output)
"""
Why don't you use shell

"""

def output_shell(line):

    try:
        shell_command = Popen(line, stdout=PIPE, stderr=PIPE, shell=True)
    except OSError:
        return None
    except ValueError:
        return None

    (output, err) = shell_command.communicate()
    shell_command.wait()
    if shell_command.returncode != 0:
        print "Shell command failed to execute"
        return None
    return str(output)
三人与歌 2024-12-11 02:13:55

感谢@hernvnc、@glglgl 和@Jacques Gaudin 的回答。我修复了@hernvnc 的代码。他的版本在某些情况下会导致挂起。

import shlex
from subprocess import PIPE
from subprocess import Popen
def run(cmd, input=None):
    """Runs the given command locally and returns the output, err and exit_code."""
    if "|" in cmd:        
        cmd_parts = cmd.split('|')
    else:
        cmd_parts = []
        cmd_parts.append(cmd)
    i = 0
    p = {}
    for cmd_part in cmd_parts:
        cmd_part = cmd_part.strip()
        if i == 0:
            if input:
                p[i]=Popen(shlex.split(cmd_part),stdin=PIPE, stdout=PIPE, stderr=PIPE)
            else:
                p[i]=Popen(shlex.split(cmd_part),stdin=None, stdout=PIPE, stderr=PIPE)
        else:
            p[i]=Popen(shlex.split(cmd_part),stdin=p[i-1].stdout, stdout=PIPE, stderr=PIPE)
        i = i +1
    # close the stdin explicitly, otherwise, the following case will hang.
    if input:
        p[0].stdin.write(input)
        p[0].stdin.close()
    (output, err) = p[i-1].communicate()
    exit_code = p[0].wait()
    return str(output), str(err), exit_code

# test case below
inp = b'[  CMServer State   ]\n\nnode        node_ip         instance state\n--------------------------------------------\n1  linux172 10.90.56.172    1        Primary\n2  linux173 10.90.56.173    2        Standby\n3  linux174 10.90.56.174    3        Standby\n\n[    ETCD State     ]\n\nnode        node_ip         instance state\n--------------------------------------------------\n1  linux172 10.90.56.172    7001     StateFollower\n2  linux173 10.90.56.173    7002     StateLeader\n3  linux174 10.90.56.174    7003     StateFollower\n\n[   Cluster State   ]\n\ncluster_state   : Normal\nredistributing  : No\nbalanced        : No\ncurrent_az      : AZ_ALL\n\n[  Datanode State   ]\n\nnode        node_ip         instance state            | node        node_ip         instance state            | node        node_ip         instance state\n------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n1  linux172 10.90.56.172    6001     P Standby Normal | 2  linux173 10.90.56.173    6002     S Primary Normal | 3  linux174 10.90.56.174    6003     S Standby Normal'
cmd = "grep -E 'Primary' | tail -1 | awk '{print $3}'"

run(cmd, input=inp)

Thank @hernvnc, @glglgl, and @Jacques Gaudin for the answers. I fixed the code from @hernvnc. His version will cause hanging in some scenarios.

import shlex
from subprocess import PIPE
from subprocess import Popen
def run(cmd, input=None):
    """Runs the given command locally and returns the output, err and exit_code."""
    if "|" in cmd:        
        cmd_parts = cmd.split('|')
    else:
        cmd_parts = []
        cmd_parts.append(cmd)
    i = 0
    p = {}
    for cmd_part in cmd_parts:
        cmd_part = cmd_part.strip()
        if i == 0:
            if input:
                p[i]=Popen(shlex.split(cmd_part),stdin=PIPE, stdout=PIPE, stderr=PIPE)
            else:
                p[i]=Popen(shlex.split(cmd_part),stdin=None, stdout=PIPE, stderr=PIPE)
        else:
            p[i]=Popen(shlex.split(cmd_part),stdin=p[i-1].stdout, stdout=PIPE, stderr=PIPE)
        i = i +1
    # close the stdin explicitly, otherwise, the following case will hang.
    if input:
        p[0].stdin.write(input)
        p[0].stdin.close()
    (output, err) = p[i-1].communicate()
    exit_code = p[0].wait()
    return str(output), str(err), exit_code

# test case below
inp = b'[  CMServer State   ]\n\nnode        node_ip         instance state\n--------------------------------------------\n1  linux172 10.90.56.172    1        Primary\n2  linux173 10.90.56.173    2        Standby\n3  linux174 10.90.56.174    3        Standby\n\n[    ETCD State     ]\n\nnode        node_ip         instance state\n--------------------------------------------------\n1  linux172 10.90.56.172    7001     StateFollower\n2  linux173 10.90.56.173    7002     StateLeader\n3  linux174 10.90.56.174    7003     StateFollower\n\n[   Cluster State   ]\n\ncluster_state   : Normal\nredistributing  : No\nbalanced        : No\ncurrent_az      : AZ_ALL\n\n[  Datanode State   ]\n\nnode        node_ip         instance state            | node        node_ip         instance state            | node        node_ip         instance state\n------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n1  linux172 10.90.56.172    6001     P Standby Normal | 2  linux173 10.90.56.173    6002     S Primary Normal | 3  linux174 10.90.56.174    6003     S Standby Normal'
cmd = "grep -E 'Primary' | tail -1 | awk '{print $3}'"

run(cmd, input=inp)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文