2009-09-11 7 views
73

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

foo = `cat /tmp/baz` 

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

+0

http://stackoverflow.com/questions/2924310/whats-a-good-equivalent-to-pythons-subprocess-check-call-that-returns-the-conte – jfs

Répondre

78
output = os.popen('cat /tmp/baz').read() 
+0

Je ne sais pas comment j'utiliserais ceci en dehors de l'exemple de l'OP. Aucune des réponses ici ne semble répondre à la question pure. par ex. comment exécuter une fonction resultant en une chaîne 'somemethod 'sans fonctions lambda – mckenzm

+2

@mckenzm La question concerne la capture de la sortie d'un processus externe La capture de la sortie d'une fonction Python serait une question tout à fait différente –

77

La manière la plus flexible est d'utiliser le module subprocess:

import subprocess 

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

Si vous voulez passer l'appel à travers la coquille, par exemple pour obtenir l'expansion du nom de fichier avec *, vous pouvez utiliser le paramètre shell=True. Si vous faites cela, vous devez fournir la commande sous forme de chaîne, cité/... comme vous écriraient à une invite du shell:

proc = subprocess.Popen('cat /tmp/ba* "s p a c e.txt"', shell=True, ...) 
+2

oui, c'est le seul moyen sain, vous pouvez envelopper dans une fonction afin que vous puissiez appeler quelque chose comme exécuter ("commande") –

+0

Cela ne fonctionne pas réellement pour moi, comme dans ce cas, baz est un répertoire et j'essaie d'obtenir le contenu de tous les fichiers dans ce répertoire. (faire cat/tmp/baz/* fonctionne en ticks mais pas via la méthode décrite ici) –

+6

re: "*" ne fonctionne pas; utilisez subprocess.Popen (["cat", "/ tmp/baz"], stdout = subprocess.PIPE, shell = True) à la place. Puisque l'extension glob (star) est gérée par shell, le module de sous-traitement doit utiliser dans ce cas l'expansion du shell (fournie par/bin/sh). –

3
import os 
foo = os.popen('cat /tmp/baz', 'r').read() 
+3

Ceci est l'équivalent des guillemets droits de Ruby, mais si votre problème est de lister le contenu d'un répertoire, alors ce n'est pas la meilleure façon de le faire .. – awatts

25

sth is right. Vous pouvez également utiliser os.popen(), mais lorsque le sous-processus disponible (Python 2.4+) est généralement préférable.

Cependant, contrairement à certaines langues qui l'encouragent, il est généralement considéré comme incorrect de générer un sous-processus dans lequel vous pouvez effectuer le même travail dans la langue. C'est plus lent, moins fiable et dépend de la plateforme. Votre exemple serait mieux que:

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

eta:

baz est un répertoire et je suis en train de récupérer le contenu de tous les fichiers dans ce répertoire

? chat sur un répertoire me fait 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 dans 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 ya pas de répertoires là-dedans, vous pouvez l'adapter dans un seul ligne:

path= '/tmp/baz' 
foo= ''.join(open(os.path.join(path, child), 'rb').read() for child in os.listdir(path)) 
+0

Bien que ce ne soit pas une réponse à la question, c'est la meilleure réponse pour éduquer les utilisateurs – noamtm

+0

Le titre de la question est "quel est l'équivalent de backticks" J'ai supposé que "cat" était juste un exemple de commande Cette réponse n'aide pas avec le cas général – Jason

1

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 "choisir un défaut raisonnable".

2

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 doc string pour subprocess j'ai remplacé

[ "prog", "arg"]

avec

"prog arg"

et obtenu le comportement de dilatation de la coque que l'on désirait (un «prog arg`» de la Perl)

subprocess.Popen d'impression ("ls -ld/tmp/v *", stdout = subprocess.PIPE, shell = True) .communicate() [0]


Je cesser d'utiliser un python tandis que de retour parce que j'étais ennuyé par la difficulté de faire l'équivalent de perl `cmd ...`. Je suis heureux de constater que Python a rendu cela raisonnable.

14
foo = subprocess.check_output(["cat", "/tmp/baz"]) 
+0

Meilleure façon de le faire. :) – Gandaro

+3

Ceci est le plus simple "subprocess.check_output" a été ajouté dans Python 2.7, qui a été publié en Juillet 2010, après que les autres réponses "popen" ont été g iven. –

4

Le moyen le plus simple consiste à utiliser le package de commandes.

import commands 

commands.getoutput("whoami") 

Sortie:

'bganesan'

+3

Très facile, mais le module est maintenant obsolète. –

1

Cela ne fonctionnera pas dans python3, mais python2 vous pouvez étendre str avec une méthode personnalisée __repr__ qui appelle votre commande shell et retourne comme ça:

#!/usr/bin/env python 

import os 

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

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

Whic h 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` 
+3

Aussi, vous ne devriez probablement pas faire cela * – ThorSummoner

4

A partir de Python 3.5 en avant, la méthode 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 pouvez ajouter .decode("ascii") ou .decode("utf-8") à la fin pour obtenir un str.