Equivalente di Bash Backticks in Python
Domanda
Qual è l'equivalente dei backtick trovati in Ruby e Perl in Python? Cioè, in Ruby posso farlo:
foo = `cat /tmp/baz`
Che aspetto ha l'istruzione equivalente in Python? Ho provato os.system (" cat / tmp / baz ")
ma questo mette il risultato fuori standard e mi restituisce il codice di errore di quell'operazione.
Soluzione
output = os.popen('cat /tmp/baz').read()
Altri suggerimenti
Il modo più flessibile è utilizzare il sottoprocesso
modulo:
import subprocess
out = subprocess.run(["cat", "/tmp/baz"], capture_output=True)
print("program output:", out)
capture_output
è stato introdotto in Python 3.7, per le versioni precedenti è invece possibile utilizzare la funzione speciale check_output ()
:
out = subprocess.check_output(["cat", "/tmp/baz"])
Puoi anche costruire manualmente un oggetto sottoprocesso se hai bisogno di un controllo dettagliato:
proc = subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE)
(out, err) = proc.communicate()
Tutte queste funzioni supportano parametri della parola chiave per personalizzare la modalità di esecuzione del sottoprocesso. Ad esempio, puoi usare shell = True
per eseguire il programma attraverso la shell, se hai bisogno di cose come espansioni di nomi di file di *
, ma questo viene fornito con limitazioni .
sth ha ragione . Puoi anche usare os.popen (), ma generalmente è preferibile sottoprocesso (Python 2.4+).
Tuttavia, a differenza di alcune lingue che lo incoraggiano, è generalmente considerata una cattiva forma generare un sottoprocesso in cui è possibile fare lo stesso lavoro all'interno della lingua. È più lento, meno affidabile e dipendente dalla piattaforma. Il tuo esempio sarebbe meglio come:
foo= open('/tmp/baz').read()
eta:
baz è una directory e sto cercando di ottenere il contenuto di tutti i file in quella directory
? cat su una directory mi dà un errore.
Se vuoi un elenco di file:
import os
foo= os.listdir('/tmp/baz')
Se vuoi il contenuto di tutti i file in una directory, qualcosa del tipo:
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)
oppure, se puoi essere sicuro che non ci siano directory, puoi inserirla in una riga:
path= '/tmp/baz'
foo= ''.join(open(os.path.join(path, child), 'rb').read() for child in os.listdir(path))
foo = subprocess.check_output(["cat", "/tmp/baz"])
Da Python 3.5 in poi, il modo consigliato è usare subprocess.run
. Per ottenere lo stesso comportamento che descrivi, dovresti usare:
output = subprocess.run("ls", shell=True, stdout=subprocess.PIPE).stdout
Questo restituirà un oggetto byte
. Potresti voler aggiungere .decode (" ascii ")
o .decode (" utf-8 ")
alla fine per ottenere un str
.
Il modo più semplice è usare il pacchetto comandi.
import commands
commands.getoutput("whoami")
Output:
'bganesan'
import os
foo = os.popen('cat /tmp/baz', 'r').read()
Sto usando
(6: 0) $ python --version Python 2.7.1
Uno degli esempi sopra è:
import subprocess
proc = subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print "program output:", out
Per me, questo non è riuscito ad accedere alla directory / tmp. Dopo aver esaminato la stringa di documenti per sottoprocesso ho sostituito
[" prog " ;, " arg "]
con
" prog arg "
e ha ottenuto il comportamento di espansione della shell desiderato (a prog Per`s `prog arg`)
print subprocess.Popen (" ls -ld / tmp / v * " ;, stdout = subprocess.PIPE, shell = True) .communicate () [0]
Ho smesso di usare Python qualche tempo fa perché ero infastidito dalla difficoltà di fare l'equivalente di perl `cmd ...`. Sono felice di scoprire che Python lo ha reso ragionevole.
Se si utilizza subprocess.Popen, ricordarsi di specificare bufsize. Il valore predefinito è 0, che significa "non bufferizzato", non "scegli un valore predefinito ragionevole".
Questo non funzionerà in python3, ma in python2 puoi estendere str
con un metodo __repr__
personalizzato che chiama il tuo comando shell e lo restituisce in questo modo:
#!/usr/bin/env python
import os
class Command(str):
"""Call system commands"""
def __repr__(cmd):
return os.popen(cmd).read()
Che puoi usare come
#!/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`
L'operatore backtick
(`) è stato rimosso in Python 3
. È confusamente simile a una singola citazione e difficile da scrivere su alcune tastiere. Invece del backtick
, usa la funzione integrata equivalente repr ()
.