python petit probleme avec subprocess

a marqué ce sujet comme résolu.

Bonjour, je voudrais executer une commande bash (sous linux) dans un programme python avec subprocess ma commande :

1
ldconfig -p | grep libjpeg

en python :

1
2
    cmd = ['ldconfig', '-p', '|', 'grep', 'libjpeg']
    result = subprocess.Popen(cmd, stdout=subprocess.PIPE)

cela me retourne une erreur en python. en bash cela fonctionne très bien :

1
libjpeg.so.62 (libc6,x86-64) => /usr/lib64/libjpeg.so.62

en python j’ai cette erreur :

1
ldconfig: chemin relatif `|' utilisé pour construire le cache

je sais que je dois faire une erreur dans mon code, mais je ne vois ou, si quelqu’un pouvais m’éclairer. par avance merci

Si tu executes dans ta console :

1
ldconfig -p "|" grep libjpeg

Tu devrais obtenir le même résultat qu’en python.

Subprocess n’appele pas bash, or la pipe (|) c’est du bash. Subprocess passe simplement la pipe en argument et ldconfig ne sais pas gérer.

Essaye :

1
cmd = ['bash' '-c' 'ldconfig -p | grep libjpeg']

Explication : J’appelle bash et je lui demande d’interpréter la commande bash ’ldconfig -p | …’.

+0 -0

merci pour ta réponse mais cela ne fonctionne pas :

1
2
3
4
5
    result = subprocess.Popen(cmd, stdout=subprocess.PIPE)
  File "/usr/lib64/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib64/python2.7/subprocess.py", line 1327, in _execute_child
    raise child_exception

Il n’y a pas une solution en utilisant uniquement a pipe (|), j’aime pas trop taper bash -c, car si l’utilisateur n’a pas bash mais autre chose…

@Kje, avec shell=True (merci je ne conaissais pas cette option) je n’ai plus d’erreur mais j’ai pas non plus le résultat de la commande :

1
2
3
4
cmd = ['ldconfig', '-p', '|', 'grep', 'libjpeg']
result = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
for line in result.stdout.readlines():
    print(line)

merci pour ta réponse mais cela ne fonctionne pas :

1
2
3
4
5
    result = subprocess.Popen(cmd, stdout=subprocess.PIPE)
  File "/usr/lib64/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib64/python2.7/subprocess.py", line 1327, in _execute_child
    raise child_exception

C’est curieux, j’avais oublié les virgules mais je viens d’essayer chez moi et ça marche bien. :s

Il n’y a pas une solution en utilisant uniquement a pipe (|), j’aime pas trop taper bash -c, car si l’utilisateur n’a pas bash mais autre chose…

C’est super de penser à ceux qui utilisent d’autres shells (J’en fais parti). Après, pense bien que même si l’utilisateur utilise un autre shell, bash est la plupart du temps installé.

@Kje, avec shell=True (merci je ne conaissais pas cette option) je n’ai plus d’erreur mais j’ai pas non plus le résultat de la commande :

1
2
3
4
cmd = ['ldconfig', '-p', '|', 'grep', 'libjpeg']
result = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
for line in result.stdout.readlines():
    print(line)

J’ai le même comportement, j’utilise fish. Je ne suis pas sûr par-contre qu’utiliser le shell de l’utilisateur soit la meilleur solution.

Tu peux peut-être créer 2 subprocesses et piper en python ? Ça me semble plus propre.

+0 -0

Tu peux peut-être créer 2 subprocesses et piper en python ? Ça me semble plus propre.

c’est à dire ?

mathema

Ce n’est qu’une proposition.

1
2
3
4
5
6
cmd = ['ldconfig', '-p']
result = subprocess.Popen(cmd, stdout=subprocess.PIPE)
output = subprocess.Popen(['grep', 'libjpeg'], stdin=result.stdout, stdout=subprocess.PIPE)

for line in output.stdout.readlines():
    print(line)

Je redirige stdout de ldconfig vers stdin de grep. C’est exactement ce que fait une pipe.

+1 -0

@Kje, avec shell=True (merci je ne conaissais pas cette option) je n’ai plus d’erreur mais j’ai pas non plus le résultat de la commande :

Parce que lui passer les arguments avec une liste va faire qu’il va échapper les caractères particuliers (dont le pipe probablement).

J’ai pas de quoi tester mais ça devrait fonctionner :

1
2
3
4
5
6
7
import subprocess
cmd = "ldconfig -p | grep libjpeg"

result = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)

for line in result.stdout.readlines():
    print(line.strip())

Ceci dit ache a raison, faire le pipe en Python serait mieux même si je pense qu’il est possible de le faire sans boucle for.

Au passage si c’est juste ça que tu veux faire, pas besoin de grep :

1
2
3
4
p = subprocess.Popen(["ldconfig", "-p"], stdout=subprocess.PIPE)
for l in p.stdout.readlines():
    if 'libjpeg' in l:
        print(l.strip())

(je met le strip pour virer a minima les sauts de lignes finaux)

edit: pour compléter, shell=True est DANGEREUX ! Donc si c’est vraiment l’équivalent d’un grep simple que tu veux faire : fait le en Python ! C’est plus clean et moins dangereux (et si tu veux plus compliqué, utilise une regex)

+6 -0

Salut,

Juste là-dessus, même si j’adhère avec le reste de la réponse de Kje :

edit: pour compléter, shell=True est DANGEREUX !

C’est dangereux uniquement si tu t’en sers pour balancer au shell des strings dont le contenu n’est pas contrôlé. Autrement, c’est pas plus dangereux que de se servir d’un shell normal. Je veux dire par là que savoir qu’il faut être prudent, c’est bien, mais ça sert à rien de tomber dans la psychose non plus et asséner que l’option est dangereuse sans expliquer pourquoi (en l’occurrence, c’est dans la doc avec même une explication sur comment s’en servir proprement).

+0 -0

Tu sais, on dit bien que system en C est dangereux à cause du fait qu’il utilise PATH pour lancer un executable et donc que son comportement dépend du système et de l’environement au lancement.

On peut faire executer n’importe quoi à system("sleep") de même pour subprocess en Python, avec ou sans SHELL.

Biensûr on pourrait faire system("/usr/bin/sleep") mais tout le monde ne l’a pas dans ce dossier. Et puis même, c’est faire confiance à un programme externe donc "dangereux". :nahbl:

Ça reste pas plus dangereux qu’utiliser un shell, mais le comportement du programme peut totalement changer.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte