relier plusieurs commandes Popen avec des pipes

je sais comment exécuter une commande en utilisant cmd = subprocess.Popen et ensuite subprocess.communiquer. La plupart du temps, j'utilise une chaîne tokenisée avec shlex.split 'argv' argument pour Popen. Exemple avec "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]

Toutefois, les tuyaux semblent ne pas fonctionner... Par exemple, l'exemple suivant renvoie la note:

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]

pouvez-vous me dire ce que je fais de mal s'il vous plaît?

Thx

23
demandé sur Alex Smith 2011-09-12 18:43:56

4 réponses

je pense que vous voulez instancier deux objets Popen séparés ici, l'un pour 'ls' et l'autre pour 'sed'. Vous voulez passer l'attribut stdout du premier objet Popen comme argument stdin au deuxième objet Popen.

exemple:

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

vous pouvez continuer à enchaîner de cette façon si vous avez plus de commandes:

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

voir la Documentation des sous-processus pour plus d'informations sur comment travailler avec des sous-processus.

37
répondu Alex Smith 2011-09-12 17:44:45

shlex ne divise les espaces que selon les règles de shell, mais ne traite pas des pipes.

Il convient, cependant, de cette façon:

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

selon 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

2
répondu glglgl 2017-03-09 14:48:26

j'ai fait une petite fonction pour aider avec la tuyauterie, j'espère que cela aide. Il enchaînera les Popens au besoin.

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
1
répondu hernvnc 2015-04-20 18:18:29

""" Pourquoi n'utilisez-vous pas shell

"""

def output_shell(ligne):

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)
1
répondu Russell 2017-03-21 23:38:32