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
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.
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
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
""" 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)