Question

J'ai des données que je voudrais gzip, uuencode puis imprimer en sortie standard. Ce que j'ai fondamentalement, c'est:

compressor = Popen("gzip", stdin = subprocess.PIPE, stdout = subprocess.PIPE)
encoder    = Popen(["uuencode", "dummy"], stdin = compressor.stdout)

La façon dont je transmets des données au compresseur se fait par compress.stdin.write (matériel).

Ce que je dois vraiment faire est d’envoyer un EOF au compresseur, et je ne sais pas comment le faire.

À un moment donné, j'ai essayé compresser.stdin.close () mais cela ne fonctionne pas - cela fonctionne bien lorsque le compresseur écrit directement dans un fichier, mais dans le cas ci-dessus, le processus ne se termine pas et s'arrête on compressor.wait ().

Des suggestions? Dans ce cas, gzip est un exemple et je dois vraiment faire quelque chose avec la canalisation de la sortie d’un processus à un autre.

Remarque: les données que je dois compresser ne tiendront pas dans la mémoire. Par conséquent, la communication n'est pas vraiment une bonne option ici. Aussi, si je viens de courir

compressor.communicate("Testing") 

après les 2 lignes ci-dessus, il se bloque toujours avec l'erreur

  File "/usr/lib/python2.4/subprocess.py", line 1041, in communicate
    rlist, wlist, xlist = select.select(read_set, write_set, [])
Était-ce utile?

La solution

Je suppose que le problème vient de l'ordre dans lequel vous ouvrez les tuyaux. UUEncode est amusant, c’est qu’il gémira quand vous le lancerez s’il n’ya pas de pipe entrante dans le bon sens (essayez de lancer le vêtement par soi-même dans un appel Popen pour voir l’explosion avec juste PIPE comme stdin et stdout)

Essayez ceci:

encoder = Popen(["uuencode", "dummy"], stdin=PIPE, stdout=PIPE)
compressor = Popen("gzip", stdin=PIPE, stdout=encoder.stdin)

compressor.communicate("UUencode me please")
encoded_text = encoder.communicate()[0]
print encoded_text

begin 644 dummy
F'XL(`%]^L$D``PL-3<U+SD])5<A-52C(24TL3@4`;2O+"!(`````
`
end

Vous avez raison, btw ... il n’ya aucun moyen d’envoyer un fichier EOF générique dans un canal. Après tout, chaque programme définit vraiment son propre fichier EOF. Pour ce faire, fermez le tuyau, comme vous tentiez de le faire.

EDIT: Je devrais être plus clair à propos de uuencode. En tant que programme shell, son comportement par défaut est d’attendre une entrée de la console. Si vous le lancez sans "live" tuyau entrant, il bloquera l’attente pour l’entrée de la console. En ouvrant le codeur en second lieu, avant que vous ayez envoyé du matériel dans le tuyau du compresseur, le codeur bloquait en attendant que vous commenciez à taper. Jerub avait raison en ce qu'il bloquait quelque chose.

Autres conseils

Ce n’est pas le genre de chose que vous devriez faire directement en python, il ya des excentricités concernant le fonctionnement des choses qui en font une bien meilleure idée de le faire avec un shell. Si vous ne pouvez utiliser que subprocess.Popen ("foo | bar", shell = True), tant mieux.

Ce qui pourrait arriver, c’est que gzip n’a pas encore été en mesure de générer toutes ses entrées et que le processus ne se terminera pas tant que ses écritures stdout ne seront pas terminées.

Vous pouvez voir quel appel système un processus bloque si vous utilisez strace. Utilisez ps auxwf pour découvrir quel processus correspond au processus gzip, puis utilisez strace -p $ pidnum pour voir quel appel système il est exécuté. Notez que stdin est FD 0 et stdout est FD 1, vous le verrez probablement en lecture ou en écriture sur ces descripteurs de fichier.

si vous souhaitez simplement compresser et n'avez pas besoin des wrappers, envisagez d'utiliser le module zlib

import zlib
compressed = zlib.compress("text")

pourquoi les suggestions shell = True et Unix ne fonctionnent-elles pas?

from subprocess import *

pipes = Popen("gzip | uuencode dummy", stdin=PIPE, stdout=PIPE, shell=True)
for i in range(1, 100):
    pipes.stdin.write("some data")
pipes.stdin.close()
print pipes.stdout.read()

semble fonctionner

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top