it-swarm-eu.dev

Chiamando un comando esterno in Python

Come posso chiamare un comando esterno (come se l'avessi inserito nella shell Unix o nel prompt dei comandi di Windows) da uno script Python?

4038
freshWoWer

Guarda il subprocess module nella libreria standard:

import subprocess
subprocess.run(["ls", "-l"])

Il vantaggio di subprocess vs. system è che è più flessibile (puoi ottenere lo stdout, lo stderr, il codice di stato "reale", una migliore gestione degli errori, ecc ...).

La documentazione ufficiale raccomanda il modulo subprocess sopra l'alternativa os.system ():

Il modulo subprocess fornisce strutture più potenti per generare nuovi processi e recuperare i loro risultati; usando quel modulo è preferibile usare questa funzione [ os.system() ].

La sezione " Sostituzione di funzioni precedenti con il modulo secondario " nella documentazione sottoprocesso potrebbe contenere alcune utili ricette.

3905
David Cournapeau

Ecco un riepilogo dei modi per chiamare i programmi esterni e i vantaggi e gli svantaggi di ciascuno:

  1. os.system("some_command with args") passa il comando e gli argomenti alla shell del sistema. Questo è bello perché è possibile 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, mentre questo è conveniente, devi gestire manualmente l'escape dei caratteri di Shell come spazi, ecc. D'altra parte, questo ti permette anche di eseguire comandi che sono semplicemente comandi di Shell e non programmi effettivamente esterni. Vedi la documentazione .

  2. stream = os.popen("some_command with args") farà la stessa cosa di os.system tranne per il fatto che ti dà un oggetto simile a un file che puoi usare per accedere a input/output standard per quel processo. Ci sono altre 3 varianti di popen che gestiscono l'I/O in modo leggermente diverso. Se passi tutto come una stringa, il tuo comando viene passato alla Shell; se li passi come elenco, non devi preoccuparti di sfuggire a qualcosa. Vedi la documentazione .

  3. La classe Popen del modulo subprocess. Questo è inteso come una sostituzione per os.popen ma ha il rovescio della medaglia di essere leggermente più complicato in virtù di essere così completo. Ad esempio, potresti dire:

    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. Vedi la documentazione .

  4. La funzione call dal modulo subprocess. Questo è fondamentalmente simile alla classe Popen e prende tutti gli stessi argomenti, ma semplicemente attende il completamento del comando e ti dà il codice di ritorno. Per esempio:

    return_code = subprocess.call("echo Hello World", Shell=True)  
    

    Vedi la documentazione .

  5. Se sei su Python 3.5 o successivo, puoi usare la nuova funzione subprocess.run , che è molto simile alla precedente ma anche più flessibile e restituisce un CompletedProcess oggetto quando il comando termina l'esecuzione.

  6. Il modulo os ha anche tutte le funzioni fork/exec/spawn che avresti in un programma C, ma non è consigliabile utilizzarle direttamente.

Il modulo subprocess dovrebbe probabilmente essere quello che usi.

Infine, si prega di essere consapevoli del fatto che per tutti i metodi in cui si passa il comando finale da eseguire da Shell come stringa e si è responsabili per l'evasione. Ci sono serie implicazioni sulla sicurezza se una qualsiasi parte della stringa che passi non può essere completamente attendibile. Ad esempio, se un utente sta inserendo parte/qualsiasi parte della stringa. Se non sei sicuro, usa solo questi metodi con le costanti. Per darti un suggerimento sulle implicazioni, considera questo codice:

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

e immagina che l'utente inserisca "mia madre non mi amava && rm -rf /".

2665
Eli Courtwright

Io di solito uso:

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 ciò che vuoi con i dati stdout nella pipe. In effetti, puoi semplicemente omettere quei parametri (stdout= e stderr=) e si comporterà come os.system().

292
EmmEff

Alcuni suggerimenti sullo scollegamento del processo figlio da quello chiamante (avvio del processo figlio in background).

Supponiamo di voler avviare una lunga attività da uno script CGI, ovvero che il processo figlio debba durare più a lungo del processo di esecuzione dello script CGI.

L'esempio classico dei documenti del modulo subprocess è:

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 vuole attendere nella riga 'chiamata sottoprocesso' fino a quando longtask.py non è finito. Ma non è chiaro cosa succede dopo la riga 'un po' di codice qui 'dell'esempio.

La mia piattaforma di destinazione era freebsd, ma lo sviluppo era su Windows, quindi ho affrontato prima il problema su Windows.

Su windows (win xp), il processo genitore non finirà fino a quando longtask.py avrà terminato il suo lavoro. Non è quello che vuoi in CGI-script. Il problema non è specifico per Python, nella comunità PHP i problemi sono gli stessi.

La soluzione è passare DETACHED_PROCESS Flag di creazione processo alla funzione CreateProcess sottostante in win API . 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 note, che il flag semanticamente corretto è CREATE_NEW_CONSOLE (0x00000010) * /

Su freebsd abbiamo un altro problema: quando il processo genitore è finito, finisce anche i processi figli. E neanche quello che vuoi in CGI-script. Alcuni esperimenti hanno mostrato 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 le ragioni del comportamento su freebsd. Se qualcuno lo sa, per favore condividi le tue idee. Googling sull'avvio di processi in background in Python non fa ancora luce.

186
newtover
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 subprocess , che altre risposte hanno trattato bene.

113
Alexandra Franks

Raccomanderei di usare il modulo di sottoprocesso invece di os.system perché fa scappare la shell per te ed è quindi molto più sicuro: http://docs.python.org/library/subprocess.html

subprocess.call(['ping', 'localhost'])
113
sirwart
import os
os.system("your command")

Si noti che questo è pericoloso, dal momento che il comando non è pulito. Lascio a te il compito di google per la documentazione pertinente sui moduli 'os' e 'sys'. Ci sono un sacco di funzioni (exec * e spawn *) che faranno cose simili.

101
nimish

Ci sono molte diverse librerie che ti permettono di chiamare comandi esterni con Python. Per ogni libreria ho dato 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 tutte le librerie che ho elencato e collegato la documentazione per ognuna di esse.

Fonti:

Queste sono tutte le librerie:

Speriamo che questo ti aiuterà a prendere una decisione su quale libreria usare :)

sottoprocesso

Il sottoprocesso consente di chiamare comandi esterni e collegarli alle loro pipe di input/output/error (stdin, stdout e stderr). Il sottoprocesso è la scelta predefinita per i comandi in esecuzione, 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: esiste anche un sottoprocesso.popen). os eseguirà sempre Shell ed è una semplice alternativa per le persone che non ne hanno bisogno o che non sanno come usare 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. Questo è utile se vuoi 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 "script-like". 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 permette di generare applicazioni figlio, controllarle e trovare pattern nel loro output. Questa è un'alternativa migliore ai sottoprocessi per i comandi che si aspettano una tty su Unix.

pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo [email protected]:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')

fabric

fabric è una libreria Python 2.5 e 2.7. Permette di eseguire comandi Shell locali e remoti. Fabric è un'alternativa semplice per l'esecuzione di 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

envoy

l'inviato è noto come "sottoprocesso per gli umani". Viene utilizzato come comodo wrapper attorno al modulo subprocess.

r = envoy.run("ls -l") # Run command
r.std_out # get output

comandi

commands contiene le funzioni wrapper per os.popen, ma è stato rimosso da Python 3 poiché subprocess è un'alternativa migliore.

La modifica era basata sul commento di J.F. Sebastian.

63
Tom Fuller

Io uso sempre fabric per 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 subprocess Python) .

Guarda un esempio:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)
60
Jorge E. Cardona

Controlla anche la libreria Python "pexpect".

Permette 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')
59
athanassis

Se hai bisogno dell'output dal comando che stai chiamando, Allora 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'

Notare anche il parametro Shell .

Se Shell è True, il comando specificato verrà eseguito tramite Shell. Questo 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 comunque un comodo accesso ad altre funzionalità di Shell quali pipe Shell, caratteri jolly del nome file, espansione della variabile di ambiente ed espansione di ~ alla home di un utente directory. Tuttavia, si noti che Python stesso offre implementazioni di molte funzionalità simili a Shell (in particolare, glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser() e shutil).

53
Facundo Casco

Con la libreria standard

Il Utilizza modulo sottoprocesso (Python 3):

import subprocess
subprocess.run(['ls', '-l'])

È il metodo standard raccomandato. Tuttavia, compiti più complicati (pipe, output, input, ecc.) Possono essere noiosi da costruire e scrivere.

Note sulla versione Python: se stai ancora usando Python 2, subprocess.call funziona in modo simile.

ProTip: shlex.split può aiutarti a analizzare il comando per run, call e altre subprocess funzioni nel caso in cui tu non voglia (o tu non possa!) Fornirle in forma di liste :

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

Con dipendenze esterne

Se non ti preoccupi delle dipendenze esterne, usa plumbum :

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

È il miglior wrapper subprocess. È multipiattaforma, cioè funziona su entrambi i sistemi Windows e Unix. Installa da pip install plumbum.

Un'altra popolare libreria è sh :

from sh import ifconfig
print(ifconfig('wlan0'))

Tuttavia, sh ha abbandonato il supporto di Windows, quindi non è fantastico come un tempo. Installa da pip install sh.

51
Honza Javorek

Ecco come eseguo i miei comandi. Questo codice ha tutto ciò che ti serve più o meno

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()
45
Usman Khan

Aggiornare:

subprocess.run è l'approccio raccomandato a partire da Python 3.5 se il tuo codice non ha bisogno di mantenere la compatibilità con le versioni precedenti di Python. È più coerente e offre una facilità d'uso simile a quella di Envoy. (Piping non è così semplice. Vedi questa domanda per come .)

Ecco alcuni esempi da i documenti .

Esegui un processo:

>>> subprocess.run(["ls", "-l"])  # doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

Rilancia su una corsa fallita:

>>> 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 l'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')

Risposta originale:

Consiglio di provare Envoy . È un wrapper per sottoprocesso, che a sua volta mira a sostituire i vecchi moduli e funzioni. Envoy è un sottoprocesso per gli umani.

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
''

Pipe in giro anche:

>>> r = envoy.run('uptime | pbcopy')

>>> r.command
'pbcopy'
>>> r.status_code
0

>>> r.history
[<Response 'uptime'>]
42
Joe

Senza l'output del risultato:

import os
os.system("your command here")

Con l'output del risultato:

import commands
commands.getoutput("your command here")
or
commands.getstatusoutput("your command here")
34
Zuckonit

https://docs.python.org/2/library/subprocess.html

... o per un comando molto semplice:

import os
os.system('cat testfile')
28
Ben Hoffstein

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
27
stuckintheshuck

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 .

27
Martin W

Chiamando un comando esterno in Python

Semplice, usa subprocess.run, che restituisce un oggetto CompletedProcess:

>>> 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)

Perché?

A partire da Python 3.5, la documentazione raccomanda subprocess.run :

L'approccio consigliato 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 di Popen sottostante può essere utilizzata direttamente.

Ecco un esempio dell'uso 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 il completamento del comando, quindi restituisce un oggetto CompletedProcess. Può invece aumentare TimeoutExpired (se gli dai un argomento timeout=) o CalledProcessError (se fallisce e passi check=True).

Come puoi 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

Catturare l'output

Se si desidera acquisire l'output, è possibile passare subprocess.PIPE al stderr o stdout appropriato:

>>> 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 inserite in stderr anziché in stdout).

Passare una lista di comandi

Si potrebbe facilmente passare dal fornire manualmente una stringa di comando (come la domanda suggerisce) a fornire una stringa costruita a livello di codice. Non costruire 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 deve essere passato in modo posizionale.

Firma completa

Ecco la vera firma nel codice sorgente e come mostrato da help(run):

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

popenargs e kwargs sono dati al costruttore Popen. input può essere una stringa di byte (o unicode, se specifica la codifica o universal_newlines=True) che verrà reindirizzato allo stdin del sottoprocesso.

La documentazione descrive timeout= e check=True meglio di quanto potrei:

L'argomento di timeout viene passato a Popen.communicate (). Se il timeout scade, il processo figlio verrà ucciso e atteso. Il L'eccezione di TimeoutExpired verrà controrilanciata dopo che il processo secondario ha terminato.

Se check è true e il processo termina con un codice di uscita diverso da zero, a L'eccezione CalledProcessError verrà sollevata. Attributi di quello eccezione tenere gli argomenti, il codice di uscita, e stdout e stderr if sono stati catturati.

e questo esempio per check=True è migliore di quello che potrei inventare:

>>> subprocess.run("exit 1", Shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Firma espansa

Ecco una firma espansa, 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 questo indica che solo l'elenco di argomenti deve essere passato in modo posizionale. Quindi passa gli argomenti rimanenti come argomenti per le parole chiave.

Popen

Quando invece usi Popen? Farei fatica a trovare casi d'uso basati solo sugli argomenti. L'uso diretto di Popen, tuttavia, ti darà accesso ai suoi metodi, inclusi poll, 'send_signal', 'terminate', e 'wait'.

Ecco la firma Popen come fornita in source . 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ù informativo è la documentazione Popen :

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)

Esegui un programma figlio in un nuovo processo. Su POSIX, la classe usa os.execvp () - come comportamento per eseguire il programma figlio. Su Windows, la classe utilizza la funzione Windows CreateProcess (). Gli argomenti per I popen sono come segue.

Capire la documentazione rimanente su Popen verrà lasciata come esercizio per il lettore.

24
Aaron Hall

Può essere così semplice:

import os
cmd = "your command"
os.system(cmd)
23

Uso:

import os

cmd = 'ls -al'

os.system(cmd)

os: questo modulo fornisce un modo portatile per utilizzare la funzionalità dipendente dal sistema operativo.

Per le funzioni os, here è la documentazione.

23
Priyankara

subprocess.check_call è conveniente se non si desidera testare i valori di ritorno. Genera un'eccezione su qualsiasi errore.

19
cdunn2001

Tendo ad usare subprocess 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)
18
Emil Stenström

os.system non ti permette di memorizzare i risultati, quindi se vuoi memorizzare i risultati in qualche lista o qualcosa subprocess.call funziona.

17
Saurabh Bangad

C'è un'altra differenza qui che non è menzionata in precedenza.

subprocess.Popen esegue il <comando> come sottoprocesso. Nel mio caso, ho bisogno di eseguire il file <a> che deve comunicare con un altro programma, <b>. 

Ho provato il sottoprocesso e l'esecuzione è andata a buon fine. Tuttavia <b> non ha potuto comunicare con <a> . Tutto è normale quando eseguo entrambi dal terminale.

Un altro: (NOTA: kwrite si comporta diversamente dalle altre applicazioni. Se provi il sotto con Firefox, i risultati non saranno gli stessi.)

Se provi os.system("kwrite"), il flusso del programma si blocca fino a quando l'utente non chiude kwrite. Per superare ciò ho provato invece os.system(konsole -e kwrite). Questo programma temporale continuava a scorrere, ma kwrite divenne il sottoprocesso della console.

Chiunque esegua il kwrite non è un sottoprocesso (ad esempio, nel monitor di sistema deve apparire sul bordo più a sinistra dell'albero).

17
Atinc Delican

Mi piace Shell_command per la sua semplicità. È costruito sopra il modulo di sottoprocesso.

Ecco un esempio dei documenti:

>>> 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
16
mdwhatcott

usa il modulo os

import os
os.system("your command")

per esempio

import os
os.system("ifconfig")
15
abhi krishnan

Plug spudorato, ho scritto una libreria per questo: P https://github.com/houqp/Shell.py

Per ora è fondamentalmente un wrapper per popen e shlex. Supporta anche i comandi di piping in modo da poterli ordinare più facilmente in Python. Quindi puoi fare cose come:

ex('echo hello Shell.py') | "awk '{print $2}'"
14
houqp

Sotto Linux, nel caso in cui si desideri chiamare un comando esterno che verrà eseguito indipendentemente (continuerà a essere eseguito dopo che lo script Python termina), è possibile utilizzare una coda semplice come spooler attività o il comando at

Un esempio con lo spooler dell'attività:

import os
os.system('ts <your-command>')

Note sullo spooler dell'attività (ts): 

  1. È possibile impostare il numero di processi concorrenti da eseguire ("slot") con:

    ts -S <number-of-slots>

  2. L'installazione di 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.

14
Yuval Atzmon

È possibile utilizzare Popen e quindi è possibile controllare lo stato della procedura:

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()

Controlla sottoprocesso.Popen .

13
admire

In Windows puoi semplicemente importare il modulo subprocess 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
12
Swadhikar C

Il modo più semplice per eseguire qualsiasi comando e ottenere il risultato:

from commands import getstatusoutput

try:
    return getstatusoutput("ls -ltr")
except Exception, e:
    return None
11
Garfield

Per recuperare l'ID di rete dal neutrone di OpenShot:

#!/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)

Output di nova net-list

+--------------------------------------+------------+------+
| 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 |
+--------------------------------------+------------+------+

Output di print (networkId)

27a74fcd-37c0-4789-9414-9531b7e3f126
11
IRSHAD

Ecco i miei due centesimi: a mio avviso, questa è la migliore pratica quando si tratta di comandi esterni ...

Questi sono i valori di ritorno dal metodo di esecuzione ...

pass, stdout, stderr = execute(["ls","-la"],"/home/user/desktop")

Questo è il metodo di esecuzione ...

def execute(cmdArray,workingDir):

    stdout = ''
    stderr = ''

    try:
        try:
            process = subprocess.Popen(cmdArray,cwd=workingDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1)
        except OSError:
            return [False, '', 'ERROR : command(' + ' '.join(cmdArray) + ') could not get executed!']

        for line in iter(process.stdout.readline, b''):

            try:
                echoLine = line.decode("utf-8")
            except:
                echoLine = str(line)

            stdout += echoLine

        for line in iter(process.stderr.readline, b''):

            try:
                echoLine = line.decode("utf-8")
            except:
                echoLine = str(line)

            stderr += echoLine

    except (KeyboardInterrupt,SystemExit) as err:
        return [False,'',str(err)]

    process.stdout.close()

    returnCode = process.wait()
    if returnCode != 0 or stderr != '':
        return [False, stdout, stderr]
    else:
        return [True, stdout, stderr]
10
Uroš Jarc

Invoke è uno strumento e libreria di esecuzione di attività Python (2.7 e 3.4+). Fornisce un'API pulita e di alto livello per l'esecuzione dei comandi Shell

>>> from invoke import run
>>> cmd = "pip install -r requirements.txt"
>>> result = run(cmd, hide=True, warn=True)
>>> print(result.ok)
True
>>> print(result.stdout.splitlines()[-1])
Successfully installed invocations-0.13.0 pep8-1.5.7 spec-1.3.1
8
Valery Ramusik

Qui sta chiamando un comando esterno e restituisce o stampa l'output del comando:

Python Sottoprocesso check_output è buono per

Esegui il comando con gli argomenti e restituisce il suo output come una stringa di byte.

import subprocess
proc = subprocess.check_output('ipconfig /all')
print proc
7
Rajiv Sharma

Uso:

import subprocess

p = subprocess.Popen("df -h", Shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")

Dà un output Nice che è più facile da lavorare:

['Filesystem      Size  Used Avail Use% Mounted on',
 '/dev/sda6        32G   21G   11G  67% /',
 'none            4.0K     0  4.0K   0% /sys/fs/cgroup',
 'udev            1.9G  4.0K  1.9G   1% /dev',
 'tmpfs           387M  1.4M  386M   1% /run',
 'none            5.0M     0  5.0M   0% /run/lock',
 'none            1.9G   58M  1.9G   3% /run/shm',
 'none            100M   32K  100M   1% /run/user',
 '/dev/sda5       340G  222G  100G  69% /home',
 '']
7
David Okwii

Solo per aggiungere alla discussione, se includi l'uso di una console Python, puoi chiamare comandi esterni da IPython . Mentre ci si trova nel prompt IPython, è possibile chiamare i comandi Shell facendo precedere '!'. È anche possibile combinare il codice Python con Shell e assegnare l'output degli script di Shell alle variabili Python.

Per esempio:

In [9]: mylist = !ls

In [10]: mylist
Out[10]:
['file1',
 'file2',
 'file3',]
7
imagineerThat

Chiamare un comando esterno in Python

Un modo semplice per chiamare un comando esterno sta usando os.system(...). E questa funzione restituisce il valore di uscita del comando. Ma lo svantaggio è che non otterremo lo stdout e lo stderr.

ret = os.system('some_cmd.sh')
if ret != 0 :
    print 'some_cmd.sh execution returned failure'

Chiamando un comando esterno in Python in background

subprocess.Popen offre più flessibilità per l'esecuzione di un comando esterno piuttosto che utilizzando os.system. Possiamo avviare un comando in background e attendere che finisca. E dopo possiamo ottenere lo stdout e lo stderr.

proc = subprocess.Popen(["./some_cmd.sh"], stdout=subprocess.PIPE)
print 'waiting for ' + str(proc.pid)
proc.wait()
print 'some_cmd.sh execution finished'
(out, err) = proc.communicate()
print 'some_cmd.sh output : ' + out

Chiamando un comando esterno di lunga esecuzione in Python in background e fermarsi dopo un po 'di tempo

Possiamo anche iniziare un processo di lunga durata in background usando subprocess.Popen e uccidilo dopo qualche tempo una volta che il suo compito è terminato.

proc = subprocess.Popen(["./some_long_run_cmd.sh"], stdout=subprocess.PIPE)
# Do something else
# Now some_long_run_cmd.sh exeuction is no longer needed, so kill it
os.system('kill -15 ' + str(proc.pid))
print 'Output : ' proc.communicate()[0]
6
rashok

Esistono molti modi diversi per eseguire comandi esterni in Python, E tutti hanno i propri lati positivi e lati negativi.

I miei colleghi e io abbiamo scritto gli strumenti di amministrazione del sistema di Python, quindi abbiamo bisogno di eseguire molti comandi esterni e, a volte, li volete bloccare o eseguire in modo asincrono, timeout, aggiornamento ogni secondo, ecc.

Esistono anche diversi modi di gestire il codice di ritorno e gli errori, E si potrebbe voler analizzare l'output e fornire un nuovo input (in un expect tipo di stile). Oppure dovrai reindirizzare stdin, stdout e stderr per l'esecuzione in un diverso tty (ad esempio, quando usi lo schermo).

Quindi probabilmente dovrai scrivere molti wrapper attorno al comando esterno. Quindi ecco un modulo Python che abbiamo scritto che può gestire Quasi tutto ciò che vorresti, e se non lo è, è molto flessibile e puoi facilmente estenderlo:

https://github.com/hpcugent/vsc-base/blob/master/lib/vsc/utils/run.py

6
Jens Timmerman

Ad esempio (in Linux):

import subprocess
subprocess.run('mkdir test.dir', Shell=True)

Questo crea test.dir nella directory corrente . Si noti che questo funziona anche:

import subprocess
subprocess.call('mkdir test.dir', Shell=True)

Il codice equivalente che utilizza os.system è:

import os
os.system('mkdir test.dir')

La migliore pratica sarebbe quella di utilizzare il sottoprocesso invece di os, con .run preferito su .call. Tutto ciò che devi sapere sul sottoprocesso è qui . Inoltre, nota che tutta la documentazione di Python è disponibile per il download da here . Ho scaricato il PDF impacchettato come .Zip. Lo dico perché c'è una bella panoramica del modulo os in tutorial.pdf (pagina 81). Inoltre, è una risorsa autorevole per i programmatori Python.

6
user8468899

Per Python 3.5+ si consiglia di utilizzare la funzione run dal modulo subprocess . Questo restituisce un oggetto CompletedProcess, da cui è possibile ottenere facilmente l'output e il codice di ritorno.

from subprocess import PIPE, run

command = ['echo', 'hello']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.returncode, result.stdout, result.stderr)
5
Chiel ten Brinke

Spesso, uso la seguente funzione per i comandi esterni, e questo è particolarmente utile per i processi lunghi in esecuzione . Il metodo seguente tails elaborerà l'output while è in esecuzione e restituisce l'output, genera un'eccezione se il processo non riesce.

Viene fuori se il processo viene eseguito usando il metodo poll () sul processo .

import subprocess,sys

def exec_long_running_proc(command, args):
    cmd = "{} {}".format(command, " ".join(str(arg) if ' ' not in arg else arg.replace(' ','\ ') for arg in args))
    print(cmd)
    process = subprocess.Popen(cmd, Shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    # Poll process for new output until finished
    while True:
        nextline = process.stdout.readline().decode('UTF-8')
        if nextline == '' and process.poll() is not None:
            break
        sys.stdout.write(nextline)
        sys.stdout.flush()

    output = process.communicate()[0]
    exitCode = process.returncode

    if (exitCode == 0):
        return output
    else:
        raise Exception(command, exitCode, output)

Puoi invocarlo in questo modo:

exec_long_running_proc(command = "Hive", args=["-f", hql_path])
5
am5

Un modo semplice è usare il modulo os:

import os
os.system('ls')

In alternativa puoi anche usare il modulo subprocess

import subprocess
subprocess.check_call('ls')

Se vuoi che il risultato sia memorizzato in una variabile prova:

import subprocess
r = subprocess.check_output('ls')
4
amehta

Usa subprocess.call :

from subprocess import call

# using list
call(["echo", "Hello", "world"])

# single string argument varies across platforms so better split it
call("echo Hello world".split(" "))
4
andruso

L'uso della funzione Popen del modulo Python subprocess è il modo più semplice per eseguire i comandi di Linux. In questo modo, la funzione Popen.communicate() darà i tuoi comandi in uscita. Per esempio

import subprocess

..
process = subprocess.Popen(..)   # Pass command and arguments to the function
stdout, stderr = process.communicate()   # Get command output and error
..
4
Asif Hasnain

Ci sono molti modi per chiamare un comando.

  • Per esempio:

se and.exe ha bisogno di due parametri. In cmd possiamo chiamare sample.exe usare questo: and.exe 2 3 e mostra 5 sullo schermo.

Se usiamo uno script Python per chiamare and.exe, dovremmo fare come ..

  1. os.system(cmd,...)

    • os.system(("and.exe" + " " + "2" + " " + "3"))
  2. os.popen(cmd,...)

    • os.popen(("and.exe" + " " + "2" + " " + "3"))
  3. subprocess.Popen(cmd,...)
    • subprocess.Popen(("and.exe" + " " + "2" + " " + "3"))

È troppo difficile, quindi possiamo unirci a cmd con uno spazio:

import os
cmd = " ".join(exename,parameters)
os.popen(cmd)
4
liuyip

Se hai bisogno di chiamare un comando Shell da un blocco note Python (come Jupyter , Zeppelin, Databricks o Google Cloud Datalab) puoi semplicemente usare il prefisso !.

Per esempio,

!ls -ilF
3
dportman

Ho scritto una piccola biblioteca per aiutare con questo caso d'uso:

https://pypi.org/project/citizenshell/

Può essere installato usando 

pip install citizenshell

E poi usato come segue:

from citizenshell import sh
assert sh("echo Hello World") == "Hello World"

È possibile separare lo stdout da stderr ed estrarre il codice di uscita come segue:

result = sh(">&2 echo error && echo output && exit 13")
assert result.stdout() == ["output"]
assert result.stderr() == ["error"]
assert result.exit_code() == 13

E la cosa interessante è che non devi aspettare che la shell sottostante esca prima di iniziare l'elaborazione dell'output:

for line in sh("for i in 1 2 3 4; do echo -n 'It is '; date +%H:%M:%S; sleep 1; done", wait=False)
    print ">>>", line + "!"

stamperà le righe come sono disponibili grazie all'attesa = False

>>> It is 14:24:52!
>>> It is 14:24:53!
>>> It is 14:24:54!
>>> It is 14:24:55!

Altri esempi possono essere trovati su https://github.com/meuter/citizenshell

3
Cédric

Esistono due modi importanti in cui è possibile eseguire comandi Shell usando Python. Entrambi gli esempi riportati sotto mostrano come si può ottenere il nome della directory di lavoro attuale (pwd) usando Python. È possibile utilizzare qualsiasi altro comando Unix al posto di pwd

1.> 1o metodo: Si può usare il modulo os da python e system () function da lì per eseguire i comandi Shell in Python.

import os
os.system('pwd')

Produzione:

/Users/siddharth

1.> Secondo metodo: Un altro modo è usare il modulo sottoprocesso e call ()

import subprocess
subprocess.call('pwd')

Produzione:

/Users/siddharth
3

Vorrei raccomandare il seguente metodo 'run' e ci aiuterà a ottenere STDOUT, STDERR e lo stato di uscita come dizionario; Il chiamante di questo può leggere il ritorno del dizionario con il metodo 'run' per conoscere lo stato attuale del processo. 

  def run (cmd):
       print "+ DEBUG exec({0})".format(cmd)
       p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, Shell=True)
       (out, err) = p.communicate()
       ret        = p.wait()
       out        = filter(None, out.split('\n'))
       err        = filter(None, err.split('\n'))
       ret        = True if ret == 0 else False
       return dict({'output': out, 'error': err, 'status': ret})
  #end
2
Viswesn

Dopo alcune ricerche, ho il seguente codice che funziona molto bene per me. In pratica stampa sia lo stdout che lo stderr in tempo reale. Spero che aiuti qualcun altro che ne ha bisogno.

stdout_result = 1
stderr_result = 1


def stdout_thread(pipe):
    global stdout_result
    while True:
        out = pipe.stdout.read(1)
        stdout_result = pipe.poll()
        if out == '' and stdout_result is not None:
            break

        if out != '':
            sys.stdout.write(out)
            sys.stdout.flush()


def stderr_thread(pipe):
    global stderr_result
    while True:
        err = pipe.stderr.read(1)
        stderr_result = pipe.poll()
        if err == '' and stderr_result is not None:
            break

        if err != '':
            sys.stdout.write(err)
            sys.stdout.flush()


def exec_command(command, cwd=None):
    if cwd is not None:
        print '[' + ' '.join(command) + '] in ' + cwd
    else:
        print '[' + ' '.join(command) + ']'

    p = subprocess.Popen(
        command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
    )

    out_thread = threading.Thread(name='stdout_thread', target=stdout_thread, args=(p,))
    err_thread = threading.Thread(name='stderr_thread', target=stderr_thread, args=(p,))

    err_thread.start()
    out_thread.start()

    out_thread.join()
    err_thread.join()

    return stdout_result + stderr_result
2
Jake W

Ho scritto un wrapper per gestire gli errori e reindirizzare l'output e altre cose.

import shlex
import psutil
import subprocess

def call_cmd(cmd, stdout=sys.stdout, quiet=False, Shell=False, raise_exceptions=True, use_shlex=True, timeout=None):
    """Exec command by command line like 'ln -ls "/var/log"'
    """
    if not quiet:
        print("Run %s", str(cmd))
    if use_shlex and isinstance(cmd, (str, unicode)):
        cmd = shlex.split(cmd)
    if timeout is None:
        process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, Shell=shell)
        retcode = process.wait()
    else:
        process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, Shell=shell)
        p = psutil.Process(process.pid)
        finish, alive = psutil.wait_procs([p], timeout)
        if len(alive) > 0:
            ps = p.children()
            ps.insert(0, p)
            print('waiting for timeout again due to child process check')
            finish, alive = psutil.wait_procs(ps, 0)
        if len(alive) > 0:
            print('process {} will be killed'.format([p.pid for p in alive]))
            for p in alive:
                p.kill()
            if raise_exceptions:
                print('External program timeout at {} {}'.format(timeout, cmd))
                raise CalledProcessTimeout(1, cmd)
        retcode = process.wait()
    if retcode and raise_exceptions:
        print("External program failed %s", str(cmd))
        raise subprocess.CalledProcessError(retcode, cmd)

Puoi chiamarlo così:

cmd = 'ln -ls "/var/log"'
stdout = 'out.txt'
call_cmd(cmd, stdout)
1
Asav Patel

Il modulo subprocess descritto in precedenza da Eli è molto potente, ma la sintassi per effettuare una chiamata di sistema standard di bog e ispezionarne l'output è inutilmente prolissa.

Il modo più semplice per effettuare una chiamata di sistema è con il modulo commands (solo Linux).

> import commands
> commands.getstatusoutput("grep matter alice-in-wonderland.txt")
(0, "'Then it doesn't matter which way you go,' said the Cat.")

Il primo elemento nella tupla è il codice di ritorno del processo. Il secondo elemento è il suo output standard (e errore standard, unito).


Gli sviluppatori Python hanno "deprecato" il modulo dei comandi, ma ciò non significa che non dovresti usarlo. Solo che non lo stanno sviluppando più, il che è ok, perché è già perfetto (nella sua funzione piccola ma importante).

1
Colonel Panic

Poiché alcune delle risposte erano relative alle versioni precedenti di Python o stavano usando il modulo os.system, inserisco questa risposta per le persone come me che intendono utilizzare subprocess in python 3.5+. Quanto segue ha fatto il trucco per me su Linux:

import subprocess

#subprocess.run() returns a completed process object that can be inspected
c = subprocess.run(["ls", "-ltrh"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(c.stdout.decode('utf-8'))

Come menzionato nel documentation , PIPE valori sono sequenze di byte e per visualizzarli correttamente è necessario prendere in considerazione la decodifica. Per le versioni successive di python, text=True e encoding='utf-8' vengono aggiunti a kwargs di subprocess.run()

L'output del codice sopra indicato è:

total 113M
-rwxr-xr-x  1 farzad farzad  307 Jan 15  2018 vpnscript
-rwxrwxr-x  1 farzad farzad  204 Jan 15  2018 ex
drwxrwxr-x  4 farzad farzad 4.0K Jan 22  2018 scripts
.... # some other lines
1
Farzad Vertigo

Se seiNONusa l'input dell'utente nei comandi puoi usare questo

from os import getcwd
from subprocess import check_output
from shlex import quote

def sh(command):
    return check_output(quote(command), Shell=True, cwd=getcwd(), universal_newlines=True).strip()

E usalo come

branch = sh('git rev-parse --abbrev-ref HEAD') 

Shell=True genererà una shell, quindi puoi usare pipe e cose di questo tipo sh('ps aux | grep python'). Questo è molto utile per l'esecuzione di comandi con hardcoded e l'elaborazione dell'output. Il universal_lines=True si assicura che l'output sia restituito in una stringa anziché in binario.

cwd=getcwd() farà in modo che il comando venga eseguito con la stessa directory di lavoro dell'interprete. Questo è utile per i comandi git per funzionare come l'esempio del nome del ramo git qui sopra.

Alcune ricette

  • memoria libera in megabyte: sh('free -m').split('\n')[1].split()[1]
  • spazio libero su/in percentuale sh('df -m /').split('\n')[1].split()[4][0:-1]
  • caricamento della CPU sum(map(float, sh('ps -ef -o pcpu').split('\n')[1:])

Ma questo non è sicuro per l'input dell'utente, dai documenti:

Considerazioni sulla sicurezza

A differenza di altre funzioni popen, questa implementazione non chiamerà mai implicitamente una shell di sistema. Ciò significa che tutti i caratteri, inclusi i metacaratteri della shell, possono essere tranquillamente passati ai processi figli. Se la Shell viene invocata esplicitamente, tramite Shell = True, è responsabilità dell'applicazione assicurarsi che tutti gli spazi bianchi e i metacaratteri siano citati in modo appropriato per evitare le vulnerabilità di iniezione Shell.

Quando si utilizza Shell = True, è possibile utilizzare la funzione shlex.quote () per eseguire correttamente l'escape di spazi bianchi e metacaratteri della shell nelle stringhe che verranno utilizzate per costruire comandi Shell.

Anche l'uso di shlex.quote() è buono per mantenere un po 'paranoico quando si usano gli input utente sui comandi Shell. Un'opzione consiste nell'usare un comando hardcode per ottenere un output generico e il filtraggio in base all'input dell'utente. Ad ogni modo usando Shell=False ci si assicurerà che solo il processo esatto che si vuole eseguire sarà eseguito o si ottiene un errore No such file or directory.

Inoltre c'è un impatto sulle prestazioni su Shell=True, dai miei test sembra circa il 20% più lento di Shell=False (il valore predefinito).

In [50]: timeit("check_output('ls -l'.split(), universal_newlines=True)", number=1000, globals=globals())
Out[50]: 2.6801227919995654

In [51]: timeit("check_output('ls -l', universal_newlines=True, Shell=True)", number=1000, globals=globals())
Out[51]: 3.243950183999914
0
geckos