Esecuzione del comando shell e acquisizione dell'output


909

Voglio scrivere una funzione che eseguirà un comando shell e restituirà il suo output come stringa , non importa, si tratta di un messaggio di errore o di successo. Voglio solo ottenere lo stesso risultato che avrei ottenuto con la riga di comando.

Quale sarebbe un esempio di codice che farebbe una cosa del genere?

Per esempio:

def run_command(cmd):
    # ??????

print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'

Risposte:


1139

La risposta a questa domanda dipende dalla versione di Python che stai utilizzando. L'approccio più semplice è utilizzare la subprocess.check_outputfunzione:

>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

check_outputesegue un singolo programma che accetta solo argomenti come input. 1 Restituisce il risultato esattamente come stampato stdout. Se è necessario scrivere input su stdin, andare avanti alle sezioni runo Popen. Se si desidera eseguire comandi di shell complessi, vedere la nota shell=Truealla fine di questa risposta.

La check_outputfunzione funziona su quasi tutte le versioni di Python ancora ampiamente utilizzate (2.7+). 2 Ma per le versioni più recenti, non è più l'approccio consigliato.

Versioni moderne di Python (3.5 o successive): run

Se si utilizza Python 3.5 o versioni successive e non è necessaria la compatibilità con le versioni precedenti , si consiglia la nuova runfunzione . Fornisce un'API di alto livello molto generale per il subprocessmodulo. Per acquisire l'output di un programma, passare il subprocess.PIPEflag stdoutall'argomento della parola chiave. Quindi accedere stdoutall'attributo CompletedProcessdell'oggetto restituito :

>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

Il valore restituito è un bytesoggetto, quindi se si desidera una stringa corretta, è necessario decode. Supponendo che il processo chiamato restituisca una stringa con codifica UTF-8:

>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

Tutto questo può essere compresso in un unico liner:

>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

Se si desidera passare l'input al processo stdin, passare un bytesoggetto inputall'argomento della parola chiave:

>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'

È possibile acquisire errori passando stderr=subprocess.PIPE(acquisisci in result.stderr) o stderr=subprocess.STDOUT(acquisisci result.stdoutinsieme all'output normale). Quando la sicurezza non è un problema, è anche possibile eseguire comandi di shell più complessi passando shell=Truecome descritto nelle note di seguito.

Questo aggiunge solo un po 'di complessità, rispetto al vecchio modo di fare le cose. Ma penso che valga la pena pagare: ora puoi fare quasi tutto ciò che devi fare con la runsola funzione.

Versioni precedenti di Python (2.7-3.4): check_output

Se stai usando una versione precedente di Python o hai bisogno di una modesta compatibilità con le versioni precedenti, puoi probabilmente usare la check_outputfunzione come brevemente descritto sopra. È disponibile da Python 2.7.

subprocess.check_output(*popenargs, **kwargs)  

Prende gli stessi argomenti di Popen(vedi sotto) e restituisce una stringa contenente l'output del programma. L'inizio di questa risposta ha un esempio di utilizzo più dettagliato. In Python 3.5 e versioni successive, check_outputequivale a eseguire runcon check=Truee stdout=PIPEe restituire solo l' stdoutattributo.

Puoi passare stderr=subprocess.STDOUTper assicurarti che i messaggi di errore siano inclusi nell'output restituito, ma in alcune versioni di Python il passaggio stderr=subprocess.PIPEa check_outputpuò causare deadlock . Quando la sicurezza non è un problema, è anche possibile eseguire comandi di shell più complessi passando shell=Truecome descritto nelle note di seguito.

Se è necessario eseguire il pipe stderro passare l'input al processo, check_outputnon sarà all'altezza dell'attività. Vedi gli Popenesempi seguenti in quel caso.

Applicazioni complesse e versioni legacy di Python (2.6 e precedenti): Popen

Se hai bisogno di una profonda compatibilità con le versioni precedenti o se hai bisogno di funzionalità più sofisticate di quelle check_outputfornite, dovrai lavorare direttamente con gli Popenoggetti, che incapsulano l'API di basso livello per i sottoprocessi.

Il Popencostruttore accetta un singolo comando senza argomenti o un elenco contenente un comando come primo elemento, seguito da un numero qualsiasi di argomenti, ciascuno come elemento separato nell'elenco. shlex.splitpuò aiutare ad analizzare le stringhe in elenchi formattati in modo appropriato. Popengli oggetti accettano anche una serie di argomenti diversi per la gestione dell'IO processo e la configurazione di basso livello.

Per inviare input e acquisire output, communicateè quasi sempre il metodo preferito. Come in:

output = subprocess.Popen(["mycmd", "myarg"], 
                          stdout=subprocess.PIPE).communicate()[0]

O

>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE, 
...                                    stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo

Se impostato stdin=PIPE, communicateconsente anche di passare i dati al processo tramite stdin:

>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
...                           stderr=subprocess.PIPE,
...                           stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo

Nota La risposta di Aaron Hall , che indica che su alcuni sistemi, potrebbe essere necessario insieme stdout, stderre stdintutti a PIPE(o DEVNULL) per arrivare communicatea lavoro a tutti.

In alcuni rari casi, potrebbe essere necessario acquisire output complessi e in tempo reale. La risposta di Vartec suggerisce una via da seguire, ma metodi diversi da quelli communicatesoggetti a deadlock se non utilizzati con attenzione.

Come per tutte le funzioni di cui sopra, quando la sicurezza non è un problema, è possibile eseguire comandi di shell più complessi passando shell=True.

Appunti

1. Esecuzione dei comandi shell: l' shell=Trueargomento

Normalmente, ogni chiamata a run, check_outputo il Popencostruttore esegue un singolo programma . Ciò significa che non ci sono pipe eleganti in stile bash. Se si desidera eseguire comandi shell complessi, è possibile passare shell=True, che supportano tutte e tre le funzioni.

Tuttavia, ciò solleva problemi di sicurezza . Se stai facendo qualcosa di più di uno script leggero, potresti fare meglio a chiamare ciascun processo separatamente e passare l'output da ciascuno come input al successivo, tramite

run(cmd, [stdout=etc...], input=other_output)

O

Popen(cmd, [stdout=etc...]).communicate(other_output)

La tentazione di collegare direttamente i tubi è forte; resistergli. Altrimenti, probabilmente vedrai deadlock o dovrai fare cose bizzarre come questa .

2. Considerazioni su Unicode

check_outputrestituisce una stringa in Python 2, ma un bytesoggetto in Python 3. Vale la pena dedicare un momento a conoscere unicode se non l'hai già fatto.


5
Entrambi con check_output()e communicate()devi aspettare fino al termine del processo, con poll()l'output che viene visualizzato. Dipende davvero da cosa ti serve.
vartec,

2
Non sono sicuro se questo si applica solo alle versioni successive di Python, ma la variabile outera di tipo <class 'bytes'>per me. Per ottenere l'output come stringa, ho dovuto decodificarlo prima di stampare in questo modo:out.decode("utf-8")
PolyMesh

1
@par Non funziona per te quando passi shell=True? Per me funziona. Non hai bisogno shlex.splitquando passi shell=True. shlex.splitè per i comandi non shell. Penso che lo toglierò un po 'perché questo sta confondendo le acque.
mittente

2
Python 3.5+ consente un argomento di parole chiave universal_newlines=Trueche consente di passare ed estrarre stringhe Unicode nella codifica predefinita del sistema. In 3.7 questo è stato rinominato nel più sensato text=True.
tripleee,

2
Per Python 3.6+ è possibile utilizzare il encodingparametro di subprocess.runanziché utilizzare result.stdout.decode('utf-8'), è possibile utilizzare subprocess.run(['ls', '-l'], stdout=subprocess.PIPE, encoding='utf-8').
Pierre,

191

Questo è molto più semplice, ma funziona solo su Unix (incluso Cygwin) e Python2.7.

import commands
print commands.getstatusoutput('wc -l file')

Restituisce una tupla con (return_value, output).

Per una soluzione che funziona in Python2 e Python3, utilizzare subprocessinvece il modulo:

from subprocess import Popen, PIPE
output = Popen(["date"],stdout=PIPE)
response = output.communicate()
print response

31
Ora obsoleto, ma molto utile per le vecchie versioni di Python senza sottoprocesso.check_output
static_rtti

22
Nota che questo è specifico per Unix. Ad esempio fallirà su Windows.
Zitrax,

4
+1 Devo lavorare sulla versione antica di Python 2.4 e questo è stato MOLTO utile
javadba

1
Cos'è PIPE Dude vieni a mostrare il codice completo: subprocess.PIPE
Kyle Bridenstine

@KyleBridenstine puoi modificare le risposte.
Boris,

106

Qualcosa del genere:

def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while(True):
        # returns None while subprocess is running
        retcode = p.poll() 
        line = p.stdout.readline()
        yield line
        if retcode is not None:
            break

Nota che sto reindirizzando stderr a stdout, potrebbe non essere esattamente quello che vuoi, ma voglio anche messaggi di errore.

Questa funzione produce riga per riga man mano che vengono (normalmente dovresti aspettare che il sottoprocesso finisca per ottenere l'output nel suo insieme).

Nel tuo caso l'utilizzo sarebbe:

for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()):
    print line,

Assicurati di implementare una sorta di loop attivo per ottenere l'output per evitare il potenziale deadlock waite le callfunzioni.
André Caron,

@Silver Light: il tuo processo è probabilmente in attesa di input da parte dell'utente. Prova a fornire un PIPEvalore stdine a chiudere quel file non appena Popenritorna.
André Caron,

4
-1: è un ciclo infinito il se retcodeè 0. Il controllo dovrebbe essere if retcode is not None. Si consiglia di non cedere le stringhe vuote (anche una riga vuota è almeno un simbolo '\ n'): if line: yield line. Chiama p.stdout.close()alla fine.
jfs,

2
Ho provato il codice con ls -l / dirname e si rompe dopo aver elencato due file mentre ci sono molti più file nella directory
Vasilis

3
@fuenfundachtzig: .readlines()non ritorna fino a quando non viene letto tutto l' output e quindi si interrompe per output di grandi dimensioni che non si adatta alla memoria. Inoltre, per evitare la mancanza di dati bufferizzati dopo la chiusura del sottoprocesso, dovrebbe esserci un analogo diif retcode is not None: yield from p.stdout.readlines(); break
jfs

67

La risposta di Vartec non legge tutte le righe, quindi ho realizzato una versione che faceva:

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

L'utilizzo è uguale alla risposta accettata:

command = 'mysqladmin create test -uroot -pmysqladmin12'.split()
for line in run_command(command):
    print(line)

6
potresti usare al return iter(p.stdout.readline, b'')posto del ciclo while
jfs il

2
Questo è un uso piuttosto interessante di iter, non lo sapevo! Ho aggiornato il codice.
Max Ekman,

Sono abbastanza sicuro che stdout mantenga tutto l'output, è un oggetto stream con un buffer. Uso una tecnica molto simile per esaurire tutto l'output rimanente dopo che un Popen è stato completato, e nel mio caso, usando poll () e readline durante l'esecuzione per catturare anche l'output dal vivo.
Max Ekman,

Ho rimosso il mio commento fuorviante. Posso confermare, p.stdout.readline()può restituire l'output precedentemente vuoto non bufferizzato anche se il processo figlio è già uscito ( p.poll()non lo è None).
jfs,

Questo codice non funziona. Vedi qui stackoverflow.com/questions/24340877/...
thang

61

Questa è una soluzione complicata ma super semplice che funziona in molte situazioni:

import os
os.system('sample_cmd > tmp')
print open('tmp', 'r').read()

Un file temporaneo (qui è tmp) viene creato con l'output del comando e puoi leggere da esso l'output desiderato.

Nota aggiuntiva dai commenti: è possibile rimuovere il file tmp in caso di lavoro singolo. Se è necessario farlo più volte, non è necessario eliminare il tmp.

os.remove('tmp')

5
Hacky ma super semplice + funziona ovunque .. posso combinarlo mktempper farlo funzionare in situazioni threaded immagino
Prakash Rajagaopal,

2
Forse il metodo più veloce, ma è meglio aggiungerlo os.remove('tmp')per renderlo "senza file".
XuMuK,

@XuMuK Hai ragione nel caso di un lavoro una tantum. Se si tratta di un'opera ripetitiva, forse non è necessario eliminarla
Mehdi Saman Booy,

1
male per la concorrenza, male per le funzioni rientranti, male per non lasciare il sistema com'era prima dell'inizio (nessuna pulizia)
2mia

1
@ 2mia Ovviamente è facile per un motivo! Se si desidera utilizzare il file come una specie di memoria condivisa per letture e scritture simultanee, questa non è una buona scelta. Ma, per il s.th. come avere l'output di un comando (es. ls o find o ...) può essere una scelta buona e veloce. A proposito, se hai bisogno di una soluzione rapida per un semplice problema, è la migliore che penso. Se hai bisogno di una pipeline, i processi secondari funzionano per te in modo più efficiente.
Mehdi Saman Booy,

44

Ho avuto lo stesso problema ma ho trovato un modo molto semplice per farlo:

import subprocess
output = subprocess.getoutput("ls -l")
print(output)

Spero che ti aiuti

Nota: questa soluzione è specifica per Python3 in quanto subprocess.getoutput()non funziona in Python2


In che modo questo risolve il problema del PO? Per favore, elabora.
RamenChef,

4
Restituisce l'output del comando come stringa, semplice come quello
azhar22k

1
Ovviamente, print è un'affermazione su Python 2. Dovresti essere in grado di capire che questa è una risposta di Python 3.

2
@Dev print (s) è Python 2. valido. Subprocess.getoutput no.
user48956

2
Per la maggior parte dei casi d'uso, questo è ciò che le persone probabilmente vorranno: facile da ricordare, non è necessario decodificare i risultati, ecc. Grazie.
bwv549,

18

È possibile utilizzare i seguenti comandi per eseguire qualsiasi comando shell. Li ho usati su Ubuntu.

import os
os.popen('your command here').read()

Nota: questo è obsoleto da Python 2.6. Ora devi usare subprocess.Popen. Di seguito è riportato l'esempio

import subprocess

p = subprocess.Popen("Your command", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")


1
@FilippoVitale Grazie. Non sapevo che fosse deprecato.
Muhammad Hassan,

1
Secondo raspberrypi.stackexchange.com/questions/71547/... os.popen() è deprecato in Python 2.6, ma è non è deprecato in Python 3.x, dal momento che in 3.x è implementato utilizzando subprocess.Popen().
JL

12

Il tuo chilometraggio può variare, ho tentato la rotazione di @ senderle sulla soluzione di Vartec in Windows su Python 2.6.5, ma stavo ottenendo errori e nessun'altra soluzione ha funzionato. Il mio errore è stato: WindowsError: [Error 6] The handle is invalid.

Ho scoperto che dovevo assegnare PIPE a ogni handle per ottenerlo per restituire l'output che mi aspettavo: quanto segue ha funzionato per me.

import subprocess

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    return subprocess.Popen(cmd, 
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE).communicate()

e chiama così, ( [0]ottiene il primo elemento della tupla stdout):

run_command('tracert 11.1.0.1')[0]

Dopo aver appreso di più, credo di aver bisogno di questi argomenti di pipe perché sto lavorando su un sistema personalizzato che utilizza diversi handle, quindi ho dovuto controllare direttamente tutti gli standard.

Per interrompere i popup della console (con Windows), procedere come segue:

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    # instantiate a startupinfo obj:
    startupinfo = subprocess.STARTUPINFO()
    # set the use show window flag, might make conditional on being in Windows:
    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    # pass as the startupinfo keyword argument:
    return subprocess.Popen(cmd,
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE, 
                            startupinfo=startupinfo).communicate()

run_command('tracert 11.1.0.1')

1
Interessante: questa deve essere una cosa di Windows. Aggiungerò una nota che punta a questo nel caso in cui le persone ricevano errori simili.
Senderle,

usare DEVNULLinvece di subprocess.PIPEse non si scrive / legge da una pipe altrimenti si potrebbe bloccare il processo figlio.
jfs,

10

Ho avuto un sapore leggermente diverso dello stesso problema con i seguenti requisiti:

  1. Cattura e restituisce i messaggi STDOUT mentre si accumulano nel buffer STDOUT (cioè in tempo reale).
    • @vartec ha risolto questo in modo pitonico con il suo uso di generatori e la
      parola chiave "yield" sopra
  2. Stampa tutte le righe STDOUT ( anche se il processo termina prima che il buffer STDOUT possa essere letto completamente )
  3. Non sprecare i cicli della CPU eseguendo il polling del processo ad alta frequenza
  4. Controllare il codice di ritorno del sottoprocesso
  5. Stampa STDERR (separato da STDOUT) se viene visualizzato un codice di ritorno errore diverso da zero.

Ho combinato e ottimizzato le risposte precedenti per trovare quanto segue:

import subprocess
from time import sleep

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         shell=True)
    # Read stdout from subprocess until the buffer is empty !
    for line in iter(p.stdout.readline, b''):
        if line: # Don't print blank lines
            yield line
    # This ensures the process has completed, AND sets the 'returncode' attr
    while p.poll() is None:                                                                                                                                        
        sleep(.1) #Don't waste CPU-cycles
    # Empty STDERR buffer
    err = p.stderr.read()
    if p.returncode != 0:
       # The run_command() function is responsible for logging STDERR 
       print("Error: " + str(err))

Questo codice verrebbe eseguito come le risposte precedenti:

for line in run_command(cmd):
    print(line)

1
Ti dispiace spiegare come l'aggiunta di sleep (.1) non sprecherà i cicli della CPU?
Moataz Elmasry,

2
Se continuassimo a chiamare p.poll()senza interruzione tra le chiamate, sprecheremmo i cicli della CPU chiamando questa funzione milioni di volte. Invece, "limitiamo" il nostro loop dicendo al sistema operativo che non abbiamo bisogno di essere disturbati per il prossimo 1/10 di secondo, in modo che possa svolgere altre attività. (È possibile che anche p.poll () dorma, rendendo ridondante la nostra istruzione sleep).
The Aelfinn,

5

Dividere il comando iniziale per subprocesspotrebbe essere complicato e ingombrante.

Usa shlex.split()per aiutarti.

Comando di esempio

git log -n 5 --since "5 years ago" --until "2 year ago"

Il codice

from subprocess import check_output
from shlex import split

res = check_output(split('git log -n 5 --since "5 years ago" --until "2 year ago"'))
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

Senza shlex.split()il codice apparirebbe come segue

res = check_output([
    'git', 
    'log', 
    '-n', 
    '5', 
    '--since', 
    '5 years ago', 
    '--until', 
    '2 year ago'
])
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

1
shlex.split()è una comodità, soprattutto se non sai come funziona esattamente la quotazione nella shell; ma convertire manualmente questa stringa nella lista ['git', 'log', '-n', '5', '--since', '5 years ago', '--until', '2 year ago']non è affatto difficile se capisci il preventivo.
Tripleee,

4

Se hai bisogno di eseguire un comando shell su più file, questo ha funzionato per me.

import os
import subprocess

# Define a function for running commands and capturing stdout line by line
# (Modified from Vartec's solution because it wasn't printing all lines)
def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

# Get all filenames in working directory
for filename in os.listdir('./'):
    # This command will be run on each file
    cmd = 'nm ' + filename

    # Run the command and capture the output line by line.
    for line in runProcess(cmd.split()):
        # Eliminate leading and trailing whitespace
        line.strip()
        # Split the output 
        output = line.split()

        # Filter the output and print relevant lines
        if len(output) > 2:
            if ((output[2] == 'set_program_name')):
                print filename
                print line

Modifica: ho appena visto la soluzione di Max Persson con il suggerimento di JF Sebastian. Andò avanti e lo incorporò.


Popenaccetta una stringa, ma è necessario shell=True, o un elenco di argomenti, nel qual caso è necessario passare al ['nm', filename]posto di una stringa. Quest'ultimo è preferibile perché la shell aggiunge complessità senza fornire alcun valore qui. Passare una stringa senza shell=Trueapparentemente funziona su Windows, ma ciò potrebbe cambiare in qualsiasi versione successiva di Python.
Tripleee,

2

Secondo @senderle, se usi python3.6 come me:

def sh(cmd, input=""):
    rst = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=input.encode("utf-8"))
    assert rst.returncode == 0, rst.stderr.decode("utf-8")
    return rst.stdout.decode("utf-8")
sh("ls -a")

Agirà esattamente come se avessi eseguito il comando in bash


Stai reinventando gli argomenti delle parole chiave check=True, universal_newlines=True. In altre parole, subprocess.run()fa già tutto ciò che fa il tuo codice.
tripleee,

1

Se si utilizza il subprocessmodulo python, è possibile gestire separatamente STDOUT, STDERR e il codice di ritorno del comando. È possibile visualizzare un esempio per l'implementazione completa del chiamante del comando. Ovviamente puoi estenderlo con try..exceptse lo desideri.

La funzione seguente restituisce STDOUT, STDERR e il codice di ritorno in modo da poterli gestire nell'altro script.

import subprocess

def command_caller(command=None)
    sp = subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=False)
    out, err = sp.communicate()
    if sp.returncode:
        print(
            "Return code: %(ret_code)s Error message: %(err_msg)s"
            % {"ret_code": sp.returncode, "err_msg": err}
            )
    return sp.returncode, out, err

Un'altra scarsa reimplementazione di subprocess.run(). Non reinventare la ruota.
tripleee,

0

ad esempio, eseguire ('ls-ahl') differenziato tre / quattro possibili rendimenti e piattaforme del sistema operativo:

  1. nessun output, ma eseguito correttamente
  2. output riga vuota, eseguito correttamente
  3. corsa fallita
  4. produrre qualcosa, eseguire correttamente

funzione di seguito

def execute(cmd, output=True, DEBUG_MODE=False):
"""Executes a bash command.
(cmd, output=True)
output: whether print shell output to screen, only affects screen display, does not affect returned values
return: ...regardless of output=True/False...
        returns shell output as a list with each elment is a line of string (whitespace stripped both sides) from output
        could be 
        [], ie, len()=0 --> no output;    
        [''] --> output empty line;     
        None --> error occured, see below

        if error ocurs, returns None (ie, is None), print out the error message to screen
"""
if not DEBUG_MODE:
    print "Command: " + cmd

    # https://stackoverflow.com/a/40139101/2292993
    def _execute_cmd(cmd):
        if os.name == 'nt' or platform.system() == 'Windows':
            # set stdin, out, err all to PIPE to get results (other than None) after run the Popen() instance
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        else:
            # Use bash; the default is sh
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, executable="/bin/bash")

        # the Popen() instance starts running once instantiated (??)
        # additionally, communicate(), or poll() and wait process to terminate
        # communicate() accepts optional input as stdin to the pipe (requires setting stdin=subprocess.PIPE above), return out, err as tuple
        # if communicate(), the results are buffered in memory

        # Read stdout from subprocess until the buffer is empty !
        # if error occurs, the stdout is '', which means the below loop is essentially skipped
        # A prefix of 'b' or 'B' is ignored in Python 2; 
        # it indicates that the literal should become a bytes literal in Python 3 
        # (e.g. when code is automatically converted with 2to3).
        # return iter(p.stdout.readline, b'')
        for line in iter(p.stdout.readline, b''):
            # # Windows has \r\n, Unix has \n, Old mac has \r
            # if line not in ['','\n','\r','\r\n']: # Don't print blank lines
                yield line
        while p.poll() is None:                                                                                                                                        
            sleep(.1) #Don't waste CPU-cycles
        # Empty STDERR buffer
        err = p.stderr.read()
        if p.returncode != 0:
            # responsible for logging STDERR 
            print("Error: " + str(err))
            yield None

    out = []
    for line in _execute_cmd(cmd):
        # error did not occur earlier
        if line is not None:
            # trailing comma to avoid a newline (by print itself) being printed
            if output: print line,
            out.append(line.strip())
        else:
            # error occured earlier
            out = None
    return out
else:
    print "Simulation! The command is " + cmd
    print ""

0

L'output può essere reindirizzato a un file di testo e quindi rileggerlo.

import subprocess
import os
import tempfile

def execute_to_file(command):
    """
    This function execute the command
    and pass its output to a tempfile then read it back
    It is usefull for process that deploy child process
    """
    temp_file = tempfile.NamedTemporaryFile(delete=False)
    temp_file.close()
    path = temp_file.name
    command = command + " > " + path
    proc = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
    if proc.stderr:
        # if command failed return
        os.unlink(path)
        return
    with open(path, 'r') as f:
        data = f.read()
    os.unlink(path)
    return data

if __name__ == "__main__":
    path = "Somepath"
    command = 'ecls.exe /files ' + path
    print(execute(command))

Certo che può, ma perché vorresti; e perché dovresti usare la shell invece di passare stdout=temp_file?
Tripleee,

In realtà, in generale hai ragione, ma nel mio esempio ecls.exesembra distribuire un altro strumento da riga di comando, quindi il modo semplice non ha funzionato a volte.
MR

0

ho appena scritto un piccolo script bash per farlo usando curl

https://gist.github.com/harish2704/bfb8abece94893c53ce344548ead8ba5

#!/usr/bin/env bash

# Usage: gdrive_dl.sh <url>

urlBase='https://drive.google.com'
fCookie=tmpcookies

curl="curl -L -b $fCookie -c $fCookie"
confirm(){
    $curl "$1" | grep jfk-button-action | sed -e 's/.*jfk-button-action" href="\(\S*\)".*/\1/' -e 's/\&amp;/\&/g'
}

$curl -O -J "${urlBase}$(confirm $1)"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.