Come si chiama un comando esterno (come se lo avessi digitato alla shell Unix o al prompt dei comandi di Windows) da uno script Python?
Come si chiama un comando esterno (come se lo avessi digitato alla shell Unix o al prompt dei comandi di Windows) da uno script Python?
Risposte:
Guarda il modulo di sottoprocesso nella libreria standard:
import subprocess
subprocess.run(["ls", "-l"])
Il vantaggio di subprocess
contro system
è che è più flessibile (è possibile ottenere il stdout
, stderr
, il codice di stato "reale", migliore gestione degli errori, ecc ...).
La documentazione ufficiale raccomanda il subprocess
modulo rispetto all'alternativa os.system()
:
Il
subprocess
modulo fornisce strutture più potenti per generare nuovi processi e recuperare i loro risultati; usare quel modulo è preferibile usare questa funzione [os.system()
].
La sezione Sostituzione delle funzioni precedenti con il modulo del sottoprocesso nella subprocess
documentazione può contenere alcune ricette utili.
Per le versioni di Python precedenti alla 3.5, usare call
:
import subprocess
subprocess.call(["ls", "-l"])
shell=True
per farlo funzionare.
shell=True
, a questo scopo Python viene fornito con os.path.expandvars . Nel tuo caso si può scrivere: os.path.expandvars("$PATH")
. @SethMMorton ti preghiamo di riconsiderare il tuo commento -> Perché non usare shell = True
for
ciclo come posso farlo senza bloccare il mio script Python? Non mi interessa l'output del comando, voglio solo eseguirne molti.
subprocess
quando shell=False
, quindi utilizzare shlex.split
per un modo semplice di fare questo docs.python.org/2/library/shlex.html#shlex.split
Ecco un riepilogo dei modi per chiamare programmi esterni e i vantaggi e gli svantaggi di ciascuno:
os.system("some_command with args")
passa il comando e gli argomenti alla shell del sistema. Questo è utile perché puoi effettivamente eseguire più comandi contemporaneamente in questo modo e impostare pipe e reindirizzamento input / output. Per esempio:
os.system("some_command < input_file | another_command > output_file")
Tuttavia, sebbene ciò sia conveniente, devi gestire manualmente l'escaping di caratteri shell come spazi, ecc. D'altra parte, questo ti consente anche di eseguire comandi che sono semplicemente comandi shell e non in realtà programmi esterni. Vedere la documentazione .
stream = os.popen("some_command with args")
farà la stessa cosa, os.system
tranne per il fatto che ti dà un oggetto simile a un file che puoi usare per accedere all'input / output standard per quel processo. Esistono altre 3 varianti di popen che gestiscono tutti gli I / O in modo leggermente diverso. Se passi tutto come una stringa, il tuo comando viene passato alla shell; se li passi come un elenco, non devi preoccuparti di sfuggire a nulla. Vedere la documentazione .
La Popen
classe del subprocess
modulo. Questo è inteso come un sostituto per os.popen
ma ha il rovescio della medaglia di essere leggermente più complicato in virtù di essere così completo. Ad esempio, diresti:
print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()
invece di:
print os.popen("echo Hello World").read()
ma è bello avere tutte le opzioni lì in una classe unificata invece di 4 diverse funzioni popen. Vedere la documentazione .
La call
funzione dal subprocess
modulo. Questo è fondamentalmente proprio come la Popen
classe e accetta tutti gli stessi argomenti, ma attende semplicemente fino al completamento del comando e ti dà il codice di ritorno. Per esempio:
return_code = subprocess.call("echo Hello World", shell=True)
Vedere la documentazione .
Se utilizzi Python 3.5 o subprocess.run
versioni successive, puoi utilizzare la nuova funzione, che è molto simile alla precedente ma ancora più flessibile e restituisce un CompletedProcess
oggetto al termine dell'esecuzione del comando.
Il modulo os ha anche tutte le funzioni fork / exec / spawn che avresti in un programma C, ma non ti consiglio di usarle direttamente.
Il subprocess
modulo dovrebbe probabilmente essere quello che usi.
Infine, tieni presente che per tutti i metodi in cui passi il comando finale deve essere eseguito dalla shell come stringa e sei responsabile della sua fuga. Ci sono serie implicazioni per la sicurezza se qualsiasi parte della stringa che passi non può essere completamente attendibile. Ad esempio, se un utente sta inserendo una / parte della stringa. Se non si è sicuri, utilizzare questi metodi solo con costanti. Per darti un suggerimento delle implicazioni, considera questo codice:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
e immagina che l'utente inserisca qualcosa "mia mamma non mi amava && rm -rf /" che poteva cancellare l'intero filesystem.
open
.
subprocess.run()
. docs.python.org/3.5/library/subprocess.html#subprocess.run
subprocess.run(..)
, cosa fa esattamente "Questo non cattura stdout o stderr di default." implicare? Che dire di subprocess.check_output(..)
e STDERR?
echo
davanti alla stringa passata a Popen
? Quindi sarà il comando completo echo my mama didnt love me && rm -rf /
.
subprocess.run()
o dei suoi fratelli più grandi subprocess.check_call()
et al. Per i casi in cui questi non sono sufficienti, vedere subprocess.Popen()
. os.popen()
forse non dovrebbe essere menzionato affatto, o venire anche dopo "hacking il proprio codice fork / exec / spawn".
Implementazione tipica:
import subprocess
p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
print line,
retval = p.wait()
Sei libero di fare quello che vuoi con i stdout
dati nella pipe. In effetti, puoi semplicemente omettere quei parametri ( stdout=
e stderr=
) e si comporterà come os.system()
.
.readlines()
legge tutte le righe contemporaneamente, cioè si blocca fino a quando il sottoprocesso non esce (chiude la sua estremità del tubo). Per leggere in tempo reale (se non ci sono problemi di buffering) potresti:for line in iter(p.stdout.readline, ''): print line,
p.stdout.readline()
(nota: no s
alla fine) non vedrà alcun dato finché il figlio non riempie il suo buffer. Se il bambino non produce molti dati, l'output non sarà in tempo reale. Vedi il secondo motivo in Q: Perché non usare semplicemente una pipe (popen ())? . In questa risposta vengono fornite alcune soluzioni alternative (pexpect, pty, stdbuf)
Popen
per compiti semplici. Questo specifica anche inutilmente shell=True
. Prova una delle subprocess.run()
risposte.
Alcuni suggerimenti su come staccare il processo figlio da quello chiamante (avviare il processo figlio in background).
Supponiamo di voler avviare un'attività lunga da uno script CGI. Cioè, il processo figlio dovrebbe durare più a lungo del processo di esecuzione dello script CGI.
L'esempio classico dalla documentazione del modulo di sottoprocesso è:
import subprocess
import sys
# Some code here
pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess
# Some more code here
L'idea qui è che non si desidera attendere nella riga 'call subprocess' fino al termine di longtask.py. Ma non è chiaro cosa succede dopo la riga "altro codice qui" dall'esempio.
La mia piattaforma di destinazione era FreeBSD, ma lo sviluppo era su Windows, quindi ho affrontato prima il problema su Windows.
Su Windows (Windows XP), il processo padre non terminerà fino a quando longtask.py non avrà terminato il suo lavoro. Non è quello che vuoi in uno script CGI. Il problema non è specifico di Python; nella comunità PHP i problemi sono gli stessi.
La soluzione è passare il Flag di creazione processo DETACHED_PROCESS alla funzione CreateProcess sottostante nell'API di Windows. Se hai installato pywin32, puoi importare il flag dal modulo win32process, altrimenti dovresti definirlo tu stesso:
DETACHED_PROCESS = 0x00000008
pid = subprocess.Popen([sys.executable, "longtask.py"],
creationflags=DETACHED_PROCESS).pid
/ * UPD 2015.10.27 @eryksun in un commento sotto le note, che il flag semanticamente corretto è CREATE_NEW_CONSOLE (0x00000010) * /
Su FreeBSD abbiamo un altro problema: quando il processo padre è finito, termina anche i processi figlio. E non è nemmeno quello che vuoi in uno script CGI. Alcuni esperimenti hanno dimostrato che il problema sembrava essere nella condivisione di sys.stdout. E la soluzione di lavoro era la seguente:
pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
Non ho controllato il codice su altre piattaforme e non conosco i motivi del comportamento su FreeBSD. Se qualcuno lo sa, per favore condividi le tue idee. Cercare su Google l'avvio di processi in background in Python non fa ancora luce.
DETACHED_PROCESS
in creationflags
evita questo, impedendo al bambino di ereditare o la creazione di una console. Se invece desideri una nuova console, utilizza CREATE_NEW_CONSOLE
(0x00000010).
os.devnull
perché alcuni programmi della console si chiudono con un errore altrimenti. Creare una nuova console quando si desidera che il processo figlio interagisca con l'utente contemporaneamente al processo padre. Sarebbe confuso provare a fare entrambi in un'unica finestra.
import os
os.system("your command")
Si noti che questo è pericoloso, poiché il comando non è stato pulito. Lascio a te Google per la documentazione pertinente sui moduli "os" e "sys". Ci sono un sacco di funzioni (exec * e spawn *) che faranno cose simili.
subprocess
una soluzione leggermente più versatile e portatile. L'esecuzione di comandi esterni è ovviamente intrinsecamente non portabile (è necessario assicurarsi che il comando sia disponibile su ogni architettura che è necessario supportare) e passare l'input dell'utente come comando esterno è intrinsecamente pericoloso.
Consiglio di usare il modulo di sottoprocesso invece di os.system perché fa scappare la shell per te ed è quindi molto più sicuro.
subprocess.call(['ping', 'localhost'])
subprocess
quando shell=False
, quindi utilizzare shlex.split
per un modo semplice di fare questo docs.python.org/2/library/shlex.html#shlex.split ( è il modo raccomandato secondo i documenti docs.python.org/2/library/subprocess.html#popen-constructor )
import os
cmd = 'ls -al'
os.system(cmd)
Se si desidera restituire i risultati del comando, è possibile utilizzare os.popen
. Tuttavia, questo è deprecato dalla versione 2.6 a favore del modulo di sottoprocesso , che altre risposte hanno coperto bene.
Esistono molte librerie diverse che ti consentono di chiamare comandi esterni con Python. Per ogni libreria ho fornito una descrizione e mostrato un esempio di chiamata a un comando esterno. Il comando che ho usato come esempio è ls -l
(elenca tutti i file). Se vuoi saperne di più su una qualsiasi delle librerie che ho elencato e collegato la documentazione per ciascuna di esse.
fonti:
Queste sono tutte le librerie:
Spero che questo ti aiuti a prendere una decisione su quale libreria usare :)
sottoprocesso
Il sottoprocesso consente di chiamare comandi esterni e collegarli alle relative pipe di input / output / error (stdin, stdout e stderr). Il sottoprocesso è la scelta predefinita per l'esecuzione dei comandi, ma a volte altri moduli sono migliori.
subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command
os
os è usato per "funzionalità dipendente dal sistema operativo". Può anche essere usato per chiamare comandi esterni con os.system
e os.popen
(Nota: c'è anche un subprocess.popen). os eseguirà sempre la shell ed è una semplice alternativa per le persone che non ne hanno bisogno o non sanno come utilizzarle subprocess.run
.
os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output
sh
sh è un'interfaccia di sottoprocesso che consente di chiamare i programmi come se fossero funzioni. Ciò è utile se si desidera eseguire un comando più volte.
sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function
plumbum
plumbum è una libreria per programmi Python "simili a script". Puoi chiamare programmi come funzioni come in sh
. Plumbum è utile se si desidera eseguire una pipeline senza shell.
ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command
pexpect
pexpect ti consente di generare applicazioni figlio, controllarle e trovare modelli nel loro output. Questa è una migliore alternativa al sottoprocesso per i comandi che prevedono un tty su Unix.
pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')
tessuto
fabric è una libreria Python 2.5 e 2.7. Ti permette di eseguire comandi shell locali e remoti. Fabric è una semplice alternativa per eseguire comandi in una shell sicura (SSH)
fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output
inviato
inviato è noto come "sottoprocesso per l'uomo". È usato come involucro pratico attorno al subprocess
modulo.
r = envoy.run("ls -l") # Run command
r.std_out # get output
comandi
commands
contiene funzioni wrapper per os.popen
, ma è stato rimosso da Python 3 poiché subprocess
è un'alternativa migliore.
La modifica si basava sul commento di JF Sebastian.
Uso sempre fabric
per queste cose come:
from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )
Ma questo sembra essere un buon strumento: sh
(interfaccia sottoprocesso Python) .
Guarda un esempio:
from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)
Controlla anche la libreria "pexpect" di Python.
Consente il controllo interattivo di programmi / comandi esterni, anche ssh, ftp, telnet, ecc. Puoi semplicemente digitare qualcosa come:
child = pexpect.spawn('ftp 192.168.0.24')
child.expect('(?i)name .*: ')
child.sendline('anonymous')
child.expect('(?i)password')
Utilizzare il modulo di sottoprocesso (Python 3):
import subprocess
subprocess.run(['ls', '-l'])
È il modo standard raccomandato. Tuttavia, attività più complesse (pipe, output, input, ecc.) Possono essere noiose da costruire e scrivere.
Nota sulla versione di Python: se si sta ancora utilizzando Python 2, subprocess.call funziona in modo simile.
Suggerimento: shlex.split può aiutarti ad analizzare il comando per run
, call
e altre subprocess
funzioni nel caso tu non voglia (o non puoi!) Fornirle sotto forma di liste:
import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))
Se non ti interessano le dipendenze esterne, usa il piombo :
from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())
È il miglior subprocess
involucro. È multipiattaforma, cioè funziona sia su sistemi Windows che Unix. Installa da pip install plumbum
.
Un'altra libreria popolare è sh :
from sh import ifconfig
print(ifconfig('wlan0'))
Tuttavia, è stato sh
eliminato il supporto di Windows, quindi non è eccezionale come una volta. Installa da pip install sh
.
Se hai bisogno dell'output del comando che stai chiamando, puoi usare subprocess.check_output (Python 2.7+).
>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
Nota anche il parametro shell .
Se la shell è
True
, il comando specificato verrà eseguito attraverso la shell. Ciò può essere utile se si utilizza Python principalmente per il flusso di controllo avanzato che offre sulla maggior parte delle shell di sistema e si desidera ancora un comodo accesso ad altre funzionalità della shell come pipe di shell, caratteri jolly di file, espansione di variabili di ambiente ed espansione di ~ a casa dell'utente directory. Tuttavia, si noti che Python si offre implementazioni di molti a guscio caratteristiche (in particolareglob
,fnmatch
,os.walk()
,os.path.expandvars()
,os.path.expanduser()
, eshutil
).
check_output
richiede un elenco anziché una stringa. Se non ti affidi agli spazi tra virgolette per rendere valida la tua chiamata, il modo più semplice e leggibile per farlo è subprocess.check_output("ls -l /dev/null".split())
.
Ecco come eseguo i miei comandi. Questo codice ha praticamente tutto ciò di cui hai bisogno
from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()
subprocess.run
è l'approccio consigliato a partire da Python 3.5 se il codice non deve mantenere la compatibilità con le versioni precedenti di Python. È più coerente e offre una facilità d'uso simile a Envoy. (Le tubazioni non sono altrettanto semplici. Vedi questa domanda per come .)
Ecco alcuni esempi dalla documentazione .
Esegui un processo:
>>> subprocess.run(["ls", "-l"]) # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)
Rilancio in caso di esito negativo:
>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
Cattura output:
>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')
Consiglio di provare Envoy . È un wrapper per sottoprocessi, che a sua volta mira a sostituire i moduli e le funzioni precedenti. Envoy è un sottoprocesso per l'uomo.
Esempio di utilizzo da README :
>>> r = envoy.run('git config', data='data to pipe in', timeout=2)
>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''
Fai pipa anche intorno:
>>> r = envoy.run('uptime | pbcopy')
>>> r.command
'pbcopy'
>>> r.status_code
0
>>> r.history
[<Response 'uptime'>]
os.system
è OK, ma un po 'datato. Inoltre non è molto sicuro. Invece, prova subprocess
. subprocess
non chiama sh direttamente ed è quindi più sicuro di os.system
.
Ottieni maggiori informazioni qui .
subprocess
non rimuove tutti i problemi di sicurezza e presenta alcuni fastidiosi problemi.
Chiamare un comando esterno in Python
Semplice, utilizzare subprocess.run
, che restituisce un CompletedProcess
oggetto:
>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)
A partire da Python 3.5, la documentazione consiglia subprocess.run :
L'approccio raccomandato per invocare i sottoprocessi è utilizzare la funzione run () per tutti i casi d'uso che può gestire. Per casi d'uso più avanzati, l'interfaccia Popen sottostante può essere utilizzata direttamente.
Ecco un esempio dell'utilizzo più semplice possibile - e fa esattamente come richiesto:
>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)
run
attende che il comando termini correttamente, quindi restituisce un CompletedProcess
oggetto. Può invece sollevare TimeoutExpired
(se gli dai un timeout=
argomento) o CalledProcessError
(se fallisce e passicheck=True
).
Come si può dedurre dall'esempio precedente, stdout e stderr vengono entrambi reindirizzati al proprio stdout e stderr per impostazione predefinita.
Possiamo ispezionare l'oggetto restituito e vedere il comando che è stato dato e il codice di ritorno:
>>> completed_process.args
'python --version'
>>> completed_process.returncode
0
Se si desidera acquisire l'output, è possibile passare subprocess.PIPE
all'appropriato stderr
o stdout
:
>>> cp = subprocess.run('python --version',
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''
(Trovo interessante e leggermente controintuitivo che le informazioni sulla versione vengano messe su stderr invece che su stdout.)
Si potrebbe facilmente passare dal fornire manualmente una stringa di comando (come suggerisce la domanda) a fornire una stringa creata a livello di programmazione. Non creare stringhe a livello di codice. Questo è un potenziale problema di sicurezza. È meglio presumere che non ti fidi dell'input.
>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n This is indented.\r\n'
Nota, solo args
dovrebbe essere passato in posizione.
Ecco la firma effettiva nella fonte e come mostrato da help(run)
:
def run(*popenargs, input=None, timeout=None, check=False, **kwargs):
I popenargs
e kwargs
sono dati al Popen
costruttore. input
può essere una stringa di byte (o unicode, se specifica la codifica o universal_newlines=True
) che verrà reindirizzata allo stdin del sottoprocesso.
La documentazione descrive timeout=
e check=True
meglio di quanto potessi:
L'argomento timeout viene passato a Popen.communicate (). Se il timeout scade, il processo figlio verrà interrotto e atteso. L'eccezione TimeoutExpired verrà nuovamente sollevata al termine del processo figlio.
Se check è true e il processo termina con un codice di uscita diverso da zero, verrà sollevata un'eccezione CalledProcessError. Gli attributi di tale eccezione contengono gli argomenti, il codice di uscita e stdout e stderr se sono stati acquisiti.
e questo esempio per check=True
è migliore di uno che potrei trovare:
>>> subprocess.run("exit 1", shell=True, check=True) Traceback (most recent call last): ... subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
Ecco una firma estesa, come indicato nella documentazione:
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None)
Si noti che ciò indica che solo l'elenco args deve essere passato in posizione. Quindi passa gli argomenti rimanenti come argomenti di parole chiave.
Quando usare Popen
invece? Farei fatica a trovare un caso d'uso basato solo sugli argomenti. L'utilizzo diretto di Popen
, tuttavia, ti darebbe accesso ai suoi metodi, tra cui poll
"send_signal", "terminate" e "wait".
Ecco la Popen
firma come indicato nella fonte . Penso che questo sia l'incapsulamento più preciso delle informazioni (al contrario di help(Popen)
):
def __init__(self, args, bufsize=-1, executable=None,
stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
shell=False, cwd=None, env=None, universal_newlines=False,
startupinfo=None, creationflags=0,
restore_signals=True, start_new_session=False,
pass_fds=(), *, encoding=None, errors=None):
Ma più istruttiva è la Popen
documentazione :
subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, encoding=None, errors=None)
Eseguire un programma figlio in un nuovo processo. Su POSIX, la classe utilizza un comportamento simile a os.execvp () per eseguire il programma figlio. Su Windows, la classe utilizza la funzione CreateProcess () di Windows. Gli argomenti a Popen sono i seguenti.
La comprensione della documentazione rimanente Popen
verrà lasciata come esercizio per il lettore.
shell=True
(o meglio ancora) passare il comando come elenco.
C'è anche Plumbum
>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad() # Notepad window pops up
u'' # Notepad window is closed by user, command returns
Uso:
import os
cmd = 'ls -al'
os.system(cmd)
os: questo modulo fornisce un modo portatile di utilizzare la funzionalità dipendente dal sistema operativo.
Per ulteriori os
funzioni, ecco la documentazione.
Può essere così semplice:
import os
cmd = "your command"
os.system(cmd)
Mi piace molto shell_command per la sua semplicità. È costruito sopra il modulo di sottoprocesso.
Ecco un esempio dalla documentazione:
>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py shell_command.py test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan 391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0
C'è un'altra differenza qui che non è stata menzionata in precedenza.
subprocess.Popen
esegue il <comando> come sottoprocesso. Nel mio caso, devo eseguire il file <a> che deve comunicare con un altro programma, <b>.
Ho provato il sottoprocesso e l'esecuzione ha avuto esito positivo. Tuttavia <b> non è riuscito a comunicare con <a>. Tutto è normale quando corro entrambi dal terminale.
Ancora uno: (NOTA: kwrite si comporta in modo diverso dalle altre applicazioni. Se si prova quanto segue con Firefox, i risultati non saranno gli stessi.)
Se ci provi os.system("kwrite")
, il flusso del programma si blocca fino a quando l'utente non chiude kwrite. Per ovviare a ciò ho provato invece os.system(konsole -e kwrite)
. Questo programma a tempo continuava a scorrere, ma kwrite divenne il sottoprocesso della console.
Chiunque esegue kwrite non è un sottoprocesso (cioè nel monitor di sistema deve apparire sul bordo più a sinistra dell'albero).
os.system
non consente di archiviare risultati, quindi se si desidera memorizzare i risultati in un elenco o qualcosa del genere, a subprocess.call
funziona.
Tendo a usare il sottoprocesso insieme a shlex (per gestire l'escaping delle stringhe tra virgolette):
>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)
Spina senza vergogna, ho scritto una libreria per questo: P https://github.com/houqp/shell.py
È praticamente un involucro per popen e shlex per ora. Supporta anche i comandi di piping in modo da poter concatenare i comandi più facilmente in Python. Quindi puoi fare cose come:
ex('echo hello shell.py') | "awk '{print $2}'"
In Windows puoi semplicemente importare il subprocess
modulo ed eseguire comandi esterni chiamando subprocess.Popen()
, subprocess.Popen().communicate()
e subprocess.Popen().wait()
come di seguito:
# Python script to run a command line
import subprocess
def execute(cmd):
"""
Purpose : To execute a command and return exit status
Argument : cmd - command to execute
Return : exit_code
"""
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(result, error) = process.communicate()
rc = process.wait()
if rc != 0:
print "Error: failed to execute command:", cmd
print error
return result
# def
command = "tasklist | grep python"
print "This process detail: \n", execute(command)
Produzione:
This process detail:
python.exe 604 RDP-Tcp#0 4 5,660 K
Sotto Linux, nel caso in cui desideri chiamare un comando esterno che verrà eseguito in modo indipendente (continuerà a funzionare dopo la fine dello script python), puoi utilizzare una semplice coda come spooler di attività o il comando at
Un esempio con lo spooler di attività:
import os
os.system('ts <your-command>')
Note sullo spooler di attività ( ts
):
È possibile impostare il numero di processi simultanei da eseguire ("slot") con:
ts -S <number-of-slots>
L'installazione ts
non richiede i privilegi di amministratore. Puoi scaricarlo e compilarlo dal sorgente con un semplice make
, aggiungerlo al tuo percorso e il gioco è fatto.
ts
non è standard su nessuna distro che conosco, sebbene l'indicatore a at
sia leggermente utile. Probabilmente dovresti anche menzionare batch
. Come altrove, la os.system()
raccomandazione dovrebbe probabilmente menzionare almeno subprocess
la sostituzione consigliata.
È possibile utilizzare Popen, quindi è possibile verificare lo stato della procedura:
from subprocess import Popen
proc = Popen(['ls', '-l'])
if proc.poll() is None:
proc.kill()
Dai un'occhiata a subprocess.Popen .
Per recuperare l'id di rete da OpenStack Neutron :
#!/usr/bin/python
import os
netid = "nova net-list | awk '/ External / { print $2 }'"
temp = os.popen(netid).read() /* Here temp also contains new line (\n) */
networkId = temp.rstrip()
print(networkId)
Uscita dell'elenco di reti nova
+--------------------------------------+------------+------+
| ID | Label | CIDR |
+--------------------------------------+------------+------+
| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1 | None |
| 27a74fcd-37c0-4789-9414-9531b7e3f126 | External | None |
| 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None |
| 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal | None |
+--------------------------------------+------------+------+
Uscita di stampa (networkId)
27a74fcd-37c0-4789-9414-9531b7e3f126
os.popen()
nel 2016. Lo script Awk potrebbe essere facilmente sostituito con codice Python nativo.
echo $PATH
usandocall(["echo", "$PATH"])
, ma ha fatto eco alla stringa letterale$PATH
invece di fare qualsiasi sostituzione. So che potrei ottenere la variabile d'ambiente PATH, ma mi chiedo se c'è un modo semplice per far sì che il comando si comporti esattamente come se l'avessi eseguito in bash.