web-dev-qa-db-fra.com

Passer des guillemets doubles en Shell à subprocess.Popen ()?

J'ai essayé de passer une commande qui fonctionne dans Shell et qui ne fonctionne qu'avec des guillemets doubles littéraux dans la ligne de commande autour de l'argument "concat:file1|file2" pour ffmpeg. 

Je ne peux cependant pas faire ce travail à partir de python avec subprocess.Popen(). Quelqu'un a une idée de la façon dont on passe des guillemets dans subprocess.Popen? 

Voici le code:

command = "ffmpeg -i "concat:1.ts|2.ts" -vcodec copy -acodec copy temp.mp4"

output,error = subprocess.Popen(command, universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).communicate()

Quand je le ferai, ffmpeg ne le prendra pas autrement que par des guillemets autour du segment. Est-il possible de passer cette ligne avec succès à la commande subprocess.Popen?

37
Fight Fire With Fire

Je suggérerais d'utiliser la forme de liste d'invocation plutôt que la version de chaîne citée:

command = ["ffmpeg", "-i", "concat:1.ts|2.ts", "-vcodec", "copy",
           "-acodec", "copy", "temp.mp4"]
output,error  = subprocess.Popen(
                    command, universal_newlines=True,
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()

Cela représente plus précisément l'ensemble exact des paramètres qui vont être transmis au processus final et élimine le besoin de perdre du temps avec les citations Shell.

Cela dit, si vous voulez absolument utiliser la version chaîne, utilisez simplement des guillemets différents (et Shell=True):

command = 'ffmpeg -i "concat:1.ts|2.ts" -vcodec copy -acodec copy temp.mp4'
output,error  = subprocess.Popen(
                    command, universal_newlines=True, Shell=True,
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
37
Amber

Cela fonctionne avec python 2.7.3 La commande de rediriger stderr vers stdout a été modifiée depuis les anciennes versions de python:

Mettez ceci dans un fichier appelé test.py:

#!/usr/bin/python
import subprocess

command = 'php -r "echo gethostname();"'
p = subprocess.Popen(command, universal_newlines=True, Shell=True, 
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
text = p.stdout.read()
retcode = p.wait()
print text

Invoquez-le:

python test.py

Il affiche mon nom d’hôte, qui est apollo:

apollo

Consultez le manuel du sous-processus: http://docs.python.org/2/library/subprocess.html

5
Eric Leschinski

Utilisez des guillemets simples 'around the "whole pattern"' pour échapper automatiquement aux doublons ou explicitement "escape the \"double quotes\"". Votre problème n'a rien à voir avec Popen en tant que tel.

Pour mémoire, j’ai eu un problème particulier avec une commande list-based passée à Popen qui conserverait non les guillemets doubles appropriés autour d’un motif glob (c’est-à-dire ce qui était suggéré dans réponse acceptée ) sous Windows. Joindre la liste dans une chaîne avec ' '.join(cmd) avant de la transmettre à Popen a résolu le problème.

4
j08lue

Je travaille avec un problème similaire, avec l'exécution d'une commande relativement complexe Sur ssh. Il y avait aussi des guillemets doubles et des guillemets simples. Parce que Je transmettais la commande à travers python, ssh, powershell etc.

Si, au lieu de cela, vous pouvez simplement convertir la commande en script Shell et exécuter le scriptShell via subprocess.call/Popen/run, ces problèmes disparaîtront.

Donc, selon que vous utilisiez Windows, Linux ou Mac, placez le Suivant dans un script Shell (script.sh ou script.bat)

ffmpeg -i "concat:1.ts|2.ts" -vcodec copy -acodec copy temp.mp4

Ensuite, vous pouvez courir 

import subprocess; subprocess.call(`./script.sh`; Shell=True)

Sans avoir à vous soucier des guillemets simples, etc.

2
alpha_989

Également en conflit avec un argument de chaîne contenant des espaces et ne souhaitant pas utiliser Shell = True.

La solution consistait à utiliser des guillemets doubles pour les chaînes internes.

args = ['salt', '-G', 'environment:DEV', 'grains.setvals', '{"man_version": "man-dev-2.3"}']

try:
    p = subprocess.Popen(args, stdin=subprocess.PIPE
                             , stdout=subprocess.PIPE
                             , stderr=subprocess.PIPE
                        )
    (stdin,stderr) = p.communicate()
except (subprocess.CalledProcessError, OSError ) as err:
    exit(1)
if p.returncode != 0:
    print("Failure in returncode of command:")
0
Pieter