web-dev-qa-db-fra.com

Équivalent de Bash Backticks dans Python

Quel est l'équivalent des backticks trouvés dans Ruby et Perl en Python? C'est-à-dire, dans Ruby je peux le faire:

foo = `cat /tmp/baz`

À quoi ressemble la déclaration équivalente en Python? J'ai essayé os.system("cat /tmp/baz") mais cela met le résultat en sortie standard et me renvoie le code d'erreur de cette opération.

77
Chris Bunch
output = os.popen('cat /tmp/baz').read()
90
John Kugelman

Le moyen le plus flexible est d'utiliser le module subprocess :

import subprocess

out = subprocess.run(["cat", "/tmp/baz"], capture_output=True)
print("program output:", out)

capture_output A été introduit dans Python 3.7, pour les versions plus anciennes, la fonction spéciale check_output() peut être utilisée à la place:

out = subprocess.check_output(["cat", "/tmp/baz"])

Vous pouvez également créer manuellement un objet de sous-processus si vous avez besoin d'un contrôle à granularité fine:

proc = subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE)
(out, err) = proc.communicate()

Toutes ces fonctions prennent en charge paramètres de mots clés pour personnaliser la façon dont le sous-processus est exécuté. Vous pouvez par exemple utiliser Shell=True Pour exécuter le programme via le Shell, si vous avez besoin de choses comme des extensions de nom de fichier de *, Mais cela vient avec limitations .

81
sth

qch a raison . Vous pouvez également utiliser os.popen (), mais lorsqu'il est disponible (Python 2.4+), le sous-processus est généralement préférable.

Cependant, contrairement à certaines langues qui l'encouragent, il est généralement considéré comme une mauvaise forme de générer un sous-processus où vous pouvez faire le même travail à l'intérieur de la langue. Il est plus lent, moins fiable et dépend de la plate-forme. Votre exemple serait mieux:

foo= open('/tmp/baz').read()

eta:

baz est un répertoire et j'essaie d'obtenir le contenu de tous les fichiers de ce répertoire

? cat sur un répertoire m'obtient une erreur.

Si vous voulez une liste de fichiers:

import os
foo= os.listdir('/tmp/baz')

Si vous voulez le contenu de tous les fichiers d'un répertoire, quelque chose comme:

contents= []
for leaf in os.listdir('/tmp/baz'):
    path= os.path.join('/tmp/baz', leaf)
    if os.path.isfile(path):
        contents.append(open(path, 'rb').read())
foo= ''.join(contents)

ou, si vous pouvez être sûr qu'il n'y a pas de répertoires dedans, vous pouvez le placer dans une seule ligne:

path= '/tmp/baz'
foo= ''.join(open(os.path.join(path, child), 'rb').read() for child in os.listdir(path))
26
bobince
foo = subprocess.check_output(["cat", "/tmp/baz"])
15
jfs

A partir de Python 3.5 en avant, la manière recommandée est d'utiliser subprocess.run . Pour obtenir le même comportement que vous décrivez, vous utiliseriez:

output = subprocess.run("ls", Shell=True, stdout=subprocess.PIPE).stdout

Cela renverra un objet bytes. Vous voudrez peut-être ajouter .decode("ascii") ou .decode("utf-8") à la fin pour obtenir un str.

9
gerrit

Le moyen le plus simple est d'utiliser le package de commandes.

import commands

commands.getoutput("whoami")

Production:

"bganesan"

6
Balachander Ganesan
import os
foo = os.popen('cat /tmp/baz', 'r').read()
3
awatts

J'utilise

(6: 0) $ python --version Python 2.7.1

L'un des exemples ci-dessus est:

import subprocess
proc = subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE, Shell=True)
(out, err) = proc.communicate()
print "program output:", out

Pour moi, cela n'a pas réussi à accéder au répertoire/tmp. Après avoir regardé la chaîne doc pour le sous-processus, j'ai remplacé

["prog", "arg"]

avec

"prog arg"

et a obtenu le comportement d'expansion de Shell qui était souhaité (le "prog arg" de la Perl)

print subprocess.Popen ("ls -ld/tmp/v *", stdout = subprocess.PIPE, Shell = True) .communicate () [0]


J'ai arrêté d'utiliser python il y a quelque temps parce que j'étais ennuyé par la difficulté de faire l'équivalent de Perl `cmd ...`. Je suis heureux de trouver Python a rendu cela raisonnable.

2
funkyj

Cela ne fonctionnera pas en python3, mais en python2 vous pouvez étendre str avec une méthode __repr__ Personnalisée qui appelle votre commande Shell et la renvoie comme suit:

#!/usr/bin/env python

import os

class Command(str):
    """Call system commands"""

    def __repr__(cmd):
        return os.popen(cmd).read()

Que vous pouvez utiliser comme

#!/usr/bin/env python
from command import Command

who_i_am = `Command('whoami')`

# Or predeclare your Shell command strings
whoami = Command('whoami')
who_i_am = `whoami`
1
ThorSummoner

Si vous utilisez subprocess.Popen, n'oubliez pas de spécifier bufsize. La valeur par défaut est 0, ce qui signifie "sans tampon", et non "choisissez une valeur par défaut raisonnable".

1
George

L'opérateur backtick (`) a été supprimé dans Python 3. Il est similaire à une citation simple et difficile à taper sur certains claviers. Au lieu de backtick, utilisez la fonction intégrée équivalente repr() .

0
Pedro Lobito