Comment utiliser la commande `subprocess` avec les pipes

246

Je veux utiliser subprocess.check_output()avec ps -A | grep 'process_name'. J'ai essayé différentes solutions mais jusqu'à présent, rien n'a fonctionné. Quelqu'un peut-il me guider comment le faire?

zuberuber
la source
4
il y a psutilqui permet d'obtenir des informations de processus de manière portable.
jfs

Réponses:

439

Pour utiliser un tuyau avec le subprocessmodule, vous devez passer shell=True.

Cependant, ce n'est pas vraiment conseillé pour diverses raisons, dont la sécurité n'est pas la moindre. Au lieu de cela, créez les processus pset grepséparément et dirigez la sortie de l'un vers l'autre, comme suit:

ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE)
output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout)
ps.wait()

Dans votre cas particulier, cependant, la solution simple est d'appeler subprocess.check_output(('ps', '-A'))puis str.findsur la sortie.

Taymon
la source
81
+1 pour séparer la sortie / entrée pour éviter d'utilisershell=True
Nicolas
5
N'oubliez pas, l'erreur subprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1signifie simplement que rien n'a été trouvé par grep, c'est donc un comportement normal.
Serge
2
Pourquoi avons-nous besoin de ps.wait()pour quand nous avons déjà la sortie. ps.wait.__doc__attend la fin de l'enfant mais le contenu de l'enfant semble déjà placé dans la outputvariable
Papouche Guinslyzinho
3
@MakisH Vous regardez string.find, ce qui a été déprécié en faveur str.find(c'est-à-dire la méthode findsur les strobjets).
Taymon
4
note: si grepdécède prématurément; pspeut se bloquer indéfiniment s'il produit suffisamment de sortie pour remplir son tampon de tuyau OS (car vous n'avez pas appelé ps.stdout.close()le parent). Échangez l'ordre de départ, pour l'éviter
jfs
54

Ou vous pouvez toujours utiliser la méthode de communication sur les objets de sous-processus.

cmd = "ps -A|grep 'process_name'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)

La méthode de communication renvoie un tuple de la sortie standard et l'erreur standard.

jkalivas
la source
3
Je pense que l'utilisation communicateest meilleure que wait. Il y a un tel avertissement: "Cela bloquera lors de l'utilisation de stdout = PIPE et / ou stderr = PIPE et le processus enfant génère suffisamment de sortie vers un canal de telle sorte qu'il bloque l'attente de la mémoire tampon du canal du système d'exploitation pour accepter plus de données. Utilisez communic () pour éviter cela. "
Paolo
2
Pour clarifier le commentaire de Paolo ci-dessus, l'avertissement est pour attendre, pas pour communiquer - c'est-à-dire que c'est la raison pour laquelle il dit que communiquer est meilleur.
EnemyBagJones
23

Voir la documentation sur la configuration d'un pipeline à l'aide d'un sous-processus: http://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline

Je n'ai pas testé l'exemple de code suivant mais il devrait être à peu près ce que vous voulez:

query = "process_name"
ps_process = Popen(["ps", "-A"], stdout=PIPE)
grep_process = Popen(["grep", query], stdin=ps_process.stdout, stdout=PIPE)
ps_process.stdout.close()  # Allow ps_process to receive a SIGPIPE if grep_process exits.
output = grep_process.communicate()[0]
AlcubierreDrive
la source
2
Après avoir vérifié que cela a échoué, voir la réponse ci-dessous par Taymon pour quelque chose qui fonctionne sans bouger
Alvin
2
subprocess.check_output ne semble pas exister dans Python 2.6.9
RightmireM
6

La solution JKALAVIS est bonne, mais j'ajouterais une amélioration pour utiliser shlex au lieu de SHELL = TRUE. ci-dessous im grepping out Query times

#!/bin/python
import subprocess
import shlex

cmd = "dig @8.8.4.4 +notcp www.google.com|grep 'Query'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)
Daniel Smith
la source
1
Pourquoi shellx sur shell?
AFP_555
2
où est utilisé shlex ici?
3lokh
4

Essayez également d'utiliser la 'pgrep'commande au lieu de'ps -A | grep 'process_name'

Shooe
la source
2
si vous voulez obtenir l'identifiant du processus, évidemment
Shooe
3

Vous pouvez essayer la fonctionnalité pipe dans sh.py :

import sh
print sh.grep(sh.ps("-ax"), "process_name")
amoffat
la source
-1

Après Python 3.5, vous pouvez également utiliser:

    import subprocess

    f = open('test.txt', 'w')
    process = subprocess.run(['ls', '-la'], stdout=subprocess.PIPE, universal_newlines=True)
    f.write(process.stdout)
    f.close()

L'exécution de la commande est bloquante et la sortie sera dans process.stdout .

zingi
la source