Puoi usare il modulo subprocess di Python per creare nuovi processi, connetterti al loro input e output e recuperare i codici di ritorno e/o l’output del processo. In questo articolo esploreremo le basi del modulo subprocess, tra cui come eseguire comandi esterni, reindirizzare input e output e gestire gli errori. Che tu sia alle prime armi o uno sviluppatore Python esperto, questo tutorial ti fornirà le conoscenze necessarie per usare efficacemente il modulo subprocess nei tuoi progetti.
Che cos’è Python Subprocess?
Il modulo subprocess di Python è uno strumento che ti permette di eseguire altri programmi o comandi dal tuo codice Python. Può essere usato per aprire nuovi programmi, inviare loro dati e ottenere i risultati.
Usare il modulo subprocess di Python è come impartire comandi al tuo computer tramite Python invece di digitarli direttamente nel terminale. Questo modulo semplifica l’automazione di attività e l’integrazione di altri programmi con il tuo codice Python. Per esempio, puoi usare il modulo subprocess per eseguire un comando della shell, come ls o ping, e ottenere l’output di quel comando nel tuo codice Python. Puoi anche usarlo per eseguire altri script o eseguibili Python, come i file .exe su Windows.
Inoltre, il modulo subprocess può reindirizzare l’input e l’output del processo, il che significa che puoi controllare quali dati vengono inviati al processo e quali dati vengono ricevuti da esso.
Una delle funzionalità più utili del modulo subprocess è che permette di gestire input, output ed errori (di solito su stderr) generati dal processo figlio. Con check=True viene sollevata una CalledProcessError e puoi ispezionare e.stdout/e.stderr. Questa caratteristica è considerata uno degli aspetti più potenti del modulo. Grazie a questa funzionalità, il processo di chiamata dei sottoprocessi è diventato più potente e versatile. Ad esempio, ora è possibile usare l’output del sottoprocesso come variabile nel resto dello script Python.
Quando usare Python Subprocess
Vediamo quando usare il modulo subprocess di Python.
Automazione di attività di sistema
Il modulo subprocess può essere usato per automatizzare varie attività di sistema, come eseguire backup, avviare e arrestare servizi e pianificare cron job. Ad esempio, puoi usare il modulo subprocess per eseguire il comando cp per creare un backup di un file o systemctl (Linux moderno) o service (sistemi più vecchi) per avviare e arrestare servizi. Puoi anche usare il modulo subprocess per invocare strumenti di pianificazione (come cron su Linux o Task Scheduler su Windows), ma la pianificazione in sé è gestita da quegli strumenti, non da subprocess.
Esecuzione di tool da riga di comando
Il modulo subprocess può essere usato per eseguire strumenti da riga di comando come grep, sed e awk, e processarne l’output nel tuo codice Python. Ad esempio, puoi usare il modulo subprocess per eseguire il comando grep per cercare un pattern specifico in un file e poi processarne l’output nel tuo codice Python. Questo può essere utile per attività come l’analisi dei log, l’elaborazione dei dati e la manipolazione di testo.
Esecuzione di eseguibili esterni
Il modulo subprocess può eseguire altri eseguibili, come i file .exe su Windows, e controllarne il comportamento. Ad esempio, puoi usare il modulo subprocess per eseguire un eseguibile che svolge un compito specifico e poi usare l’output di quell’eseguibile nel tuo codice. Questo può essere utile per attività di elaborazione di immagini, analisi dei dati e machine learning.
Esecuzione di script come processi in background
Puoi usare il modulo subprocess per eseguire script come processi in background, in modo che continuino a funzionare dopo l’uscita del programma principale. Ad esempio, puoi usare il modulo subprocess per eseguire uno script che svolge un compito specifico e uscire dal programma principale senza attendere il completamento dello script. Questo può essere utile per monitoraggio, logging e raccolta dati.
Esecuzione di script con interprete non-Python
Il modulo subprocess può aiutarti a eseguire script scritti in altri linguaggi come Perl, Ruby e Bash. Ad esempio, puoi usare il modulo subprocess per eseguire uno script Perl che svolge un compito specifico e poi usare l’output di quello script nel tuo codice. Questo può essere utile per elaborazione dati, manipolazione di testo e amministrazione di sistema.
Elaborazione in parallelo
Il modulo subprocess può essere usato per eseguire più processi in parallelo, utile per attività come elaborazione di immagini, analisi dei dati e machine learning. Ad esempio, puoi usare il modulo subprocess per eseguire più istanze dello stesso script, ognuna delle quali elabora una parte diversa dei dati, per poi combinare i risultati.
Esegui e modifica il codice da questo tutorial online
Esegui codiceEsempi di Python Subprocess
Vediamo ora alcuni esempi di Python subprocess.
python subprocess run
Il metodo subprocess.run() è un modo comodo per eseguire un sottoprocesso e attendere che termini. Ti permette di scegliere il comando da eseguire e aggiungere opzioni come argomenti, variabili d’ambiente e reindirizzamenti di input/output. Una volta avviato il sottoprocesso, il metodo run() blocca fino al completamento del sottoprocesso e restituisce un oggetto CompletedProcess, che contiene il codice di ritorno e l’output del sottoprocesso.
Il metodo subprocess.run() accetta diversi argomenti, tra cui:
-
args: Il comando da eseguire e i relativi argomenti, passati come lista di stringhe. -
capture_output: Se impostato a True, cattura lo standard output e lo standard error. -
text: Se impostato a True, restituisce stdout e stderr come stringhe, altrimenti come byte. -
check: un valore booleano che indica se verificare il codice di ritorno del sottoprocesso; se check è true e il codice di ritorno è diverso da zero, viene sollevataCalledProcessError. -
timeout: Un valore in secondi che specifica quanto attendere il completamento del sottoprocesso prima del timeout. -
shell: Un valore booleano che indica se eseguire il comando in una shell. Ciò significa che il comando è passato come stringa e possono essere usate funzionalità specifiche della shell, come l’espansione dei wildcard e la sostituzione di variabili.
Il metodo subprocess.run() restituisce anche un oggetto CompletedProcess, che contiene i seguenti attributi:
-
args: Il comando e gli argomenti eseguiti. -
returncode: Il codice di ritorno del sottoprocesso. -
stdout: Lo standard output del sottoprocesso (stringa se text=True, altrimenti byte). stderr: Lo standard error del sottoprocesso (stringa se text=True, altrimenti byte).
Esempio 1: Esecuzione di comandi della shell:
import subprocess
result = subprocess.run("dir", shell=True, capture_output=True, text=True)
print(result.stdout)
Output:
Volume in drive C has no label.
Volume Serial Number is E414-A41C
Directory of C:\Users\owner
01/25/2023 10:56 AM <DIR> .
01/25/2023 10:56 AM <DIR> ..
07/19/2021 01:19 PM <DIR> .anaconda
07/19/2021 01:19 PM <DIR> .astropy
07/19/2021 01:19 PM <DIR> .aws
09/12/2022 08:48 AM 496 .bash_history
03/27/2022 03:08 PM <DIR> .cache
09/26/2021 06:58 AM <DIR> .conda
09/26/2021 06:59 AM 25 .condarc
…
Su Linux/macOS, usa: result = subprocess.run(["ls", "-la"], capture_output=True, text=True) (nessun argomento shell necessario).
Esempio 2: Esecuzione di script Python:
Puoi anche eseguire uno script Python usando il metodo subprocess.run(). Cominciamo creando un semplice script Python in un file .py
print(“This is the output from subprocess module”)
Salva questo file come file_donot_exist.py. Ora puoi usare il modulo subprocess per eseguire questo file:
import subprocess
import sys
result = subprocess.run(["python", "file_donot_exist.py"], capture_output=True, text=True, check=False)
print(result.stdout)
Output:
This is the output from subprocess module
Esempio 3: Esecuzione di codice Python direttamente da una funzione:
Per casi d’uso semplici, puoi passare direttamente un comando Python nella funzione subprocess.run(). Ecco come:
result = subprocess.run([sys.executable, "-c", "print('This is directly from a subprocess.run() function')"], capture_output = True, text = True)
print(result.stdout)
Output:
This is directly from a subprocess.run() function
Nella lista args, il primo elemento sys.executable si risolve dinamicamente nel percorso dell’interprete Python in uso. Questo garantisce coerenza con il processo in esecuzione ed evita percorsi hardcoded come "C:/...". Il secondo elemento, "-c", esegue la stringa successiva come codice Python invece di uno script. Includi sempre import sys per accedere a sys.executable.
Esempio 4: Uso dell’argomento check
L’argomento check è un parametro opzionale della funzione subprocess.run() nel modulo subprocess di Python. È un valore booleano che controlla se la funzione deve verificare il codice di ritorno del comando eseguito.
Quando check è impostato su True, la funzione controllerà il codice di ritorno del comando e solleverà un’eccezione CalledProcessError se il codice di ritorno è diverso da zero. L’eccezione avrà come attributi il codice di ritorno, stdout, stderr e il comando.
Quando check è impostato su False (predefinito), la funzione non solleverà un’eccezione anche se il comando fallisce — in tal caso dovrai ispezionare tu stesso il codice di ritorno.
import subprocess
result = subprocess.run(["python", "file_donot_exist.py"], capture_output=True, text=True, check=True)
print(result.stdout)
print(result.stderr)
Output:
---------------------------------------------------------------------------
CalledProcessError Traceback (most recent call last)
<ipython-input-81-503b60184db8> in <module>
1 import subprocess
----> 2 result = subprocess.run(["python", "file_donot_exist.py"], capture_output=True, text=True, check=True)
3 print(result.stdout)
4 print(result.stderr)
~\anaconda3\lib\subprocess.py in run(input, capture_output, timeout, check, *popenargs, **kwargs)
514 retcode = process.poll()
515 if check and retcode:
--> 516 raise CalledProcessError(retcode, process.args,
517 output=stdout, stderr=stderr)
518 return CompletedProcess(process.args, retcode, stdout, stderr)
CalledProcessError: Command '['python', 'file_donot_exist.py']' returned non-zero exit status 2.
Nota che il comando non è riuscito perché my_python_file2.py non esiste e, poiché è stato passato check=True, è stata sollevata una CalledProcessError. Se imposti check=False (o lo ometti del tutto), il processo non solleverà un’eccezione; al contrario, vedrai il messaggio di errore in stderr e potrai decidere tu come gestirlo.
import subprocess
result = subprocess.run(["python", "my_python_file2.py"], capture_output=True, text=True, check=False)
print(result.stdout)
print(result.stderr)
Output:
python: can't open file 'my_python_file2.py': [Errno 2] No such file or directory
python subprocess Popen
subprocess.Popen() è un’interfaccia a livello più basso per l’esecuzione di sottoprocessi, mentre subprocess.run è un wrapper di livello più alto attorno a Popen pensato per essere più comodo da usare.
Popen ti consente di avviare un nuovo processo e interagire con i suoi stream di input, output ed error. Restituisce un handle al processo in esecuzione che può essere usato per attendere il completamento del processo, verificarne il codice di ritorno o terminarlo.
run() è una funzione più comoda che ti permette di eseguire un comando e catturarne l’output in una singola chiamata, senza dover creare un oggetto Popen e gestire personalmente gli stream. Consente anche di specificare varie opzioni per l’esecuzione del comando, come se sollevare un’eccezione in caso di fallimento.
In generale, usa run() se devi solo eseguire un comando e catturarne l’output, e Popen se ti serve un controllo maggiore sul processo, ad esempio per interagire con i suoi stream di input e output.
La classe Popen accetta gli stessi argomenti di run(), inclusi gli args che specificano il comando da eseguire e altri argomenti opzionali come stdin, stdout, stderr, shell, cwd ed env. Inoltre, la classe Popen ha diversi metodi che ti permettono di interagire con il processo, come communicate(), poll(), wait(), terminate() e kill().
import subprocess
p = subprocess.Popen(["python", "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
output, errors = p.communicate()
print(output)
Output:
usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options and arguments (and corresponding environment variables):
-b : issue warnings about str(bytes_instance), str(bytearray_instance)
and comparing bytes/bytearray with str. (-bb: issue errors)
-B : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x
-c cmd : program passed in as string (terminates option list)
-d : debug output from parser; also PYTHONDEBUG=x
-E : ignore PYTHON* environment variables (such as PYTHONPATH)
…
Questo eseguirà il comando python –help e creerà un nuovo oggetto Popen, memorizzato nella variabile p. Lo standard output e lo standard error del comando vengono catturati usando il metodo communicate() e memorizzati rispettivamente nelle variabili output ed errors.
subprocess.Popen è utile quando vuoi avere più controllo sul processo, ad esempio inviargli input, riceverne l’output o attendere che termini.
python subprocess call
subprocess.call() è una funzione del modulo subprocess di Python che viene usata per eseguire un comando in un processo separato e attendere che termini. Restituisce il codice di ritorno del comando, che è zero se il comando è andato a buon fine e diverso da zero se è fallito.
La funzione call() accetta gli stessi argomenti di run(), inclusi gli args che specificano il comando da eseguire e altri argomenti opzionali come stdin, stdout, stderr, shell, cwd ed env.
Lo standard output e lo standard error del comando vengono inviati allo stesso stdout e stderr del processo padre, a meno che non li reindirizzi usando gli argomenti stdout e stderr.
import sys
import subprocess
return_code = subprocess.call([sys.executable, "--version"])
if return_code == 0:
print("Command executed successfully.")
else:
print("Command failed with return code", return_code)
Output:
Command executed successfully.
Questo eseguirà il comando python -–version in un processo separato e attenderà che termini. Il codice di ritorno del comando verrà memorizzato nella variabile return_code, che sarà zero se il comando è andato a buon fine e diverso da zero se è fallito.
subprocess.call() è utile quando vuoi eseguire un comando e verificarne il codice di ritorno, ma non hai bisogno di catturarne l’output.
python subprocess check_output
check_output è una funzione del modulo subprocess simile a run(), ma restituisce solo lo standard output del comando e solleva un’eccezione CalledProcessError se il codice di ritorno è diverso da zero.
La funzione check_output() accetta gli stessi argomenti di run(), inclusi args (comando da eseguire) e argomenti opzionali come stdin, stderr, shell, cwd ed env. Restituisce lo standard output del comando come oggetto bytes o stringa (se text=True). Solleva CalledProcessError se il comando fallisce (uscita con stato diverso da zero).
Nota: Per impostazione predefinita, check_output() cattura solo stdout. Per includere stderr nell’output, reindirizzalo esplicitamente usando stderr=subprocess.STDOUT.
import subprocess
import sys
try:
output = subprocess.check_output([sys.executable, "--version"], text=True)
print(output)
except subprocess.CalledProcessError as e:
print(f"Command failed with return code {e.returncode}")
Output:
Python 3.8.8
Python Subprocess Pipe
Il modulo subprocess di Python fornisce un modo per creare e interagire con processi figli, che possono essere usati per eseguire altri programmi o comandi. Una delle funzionalità del modulo subprocess è la possibilità di creare pipe, che consentono la comunicazione tra processo padre e processo figlio.
Una pipe è un canale di comunicazione unidirezionale che collega lo standard output di un processo allo standard input di un altro. Una pipe può collegare l’output di un comando all’input di un altro, permettendo di usare l’output del primo comando come input del secondo.
Le pipe possono essere create usando il modulo subprocess con la classe Popen specificando l’argomento stdout o stdin come subprocess.PIPE.
Ad esempio, il seguente codice crea una pipe che collega l’output del comando ls all’input del comando grep, che filtra l’output per mostrare solo le righe che contengono la parola "file":
import subprocess
ls_process = subprocess.Popen(["ls"], stdout=subprocess.PIPE, text=True)
grep_process = subprocess.Popen(
["grep", "sample"],
stdin=ls_process.stdout,
stdout=subprocess.PIPE,
text=True
)
ls_process.stdout.close() # POSIX-only: prevents deadlocks by closing the pipe
output, error = grep_process.communicate()
print(output)
print(error)
Output:
sample_data
In questo esempio, la classe Popen viene usata per creare due processi figli, uno per il comando ls e uno per il comando grep. Lo stdout del comando ls è collegato allo stdin del comando grep usando subprocess.PIPE, che crea una pipe tra i due processi. Il metodo communicate() viene usato per inviare l’output del comando ls al comando grep e recuperare l’output filtrato.
Conclusione
Il modulo subprocess di Python offre un modo potente e flessibile per creare e interagire con processi figli, consentendoti di eseguire altri programmi o impartire comandi all’interno del tuo script Python. Dai comandi semplici come subprocess.call() a funzionalità più avanzate come le pipe, il reindirizzamento di input e output e il passaggio di variabili d’ambiente, il modulo subprocess ha qualcosa da offrire per quasi ogni caso d’uso. È un ottimo modo per automatizzare attività ripetitive, eseguire comandi di sistema e persino interagire con altri linguaggi e piattaforme.
Quando lavori con il modulo subprocess, è importante ricordare che l’esecuzione di comandi esterni comporta rischi per la sicurezza, soprattutto quando si usa il parametro shell=True o si passano input non sanificati. È sempre una buona pratica usare la funzione subprocess.run(), che ti permette di specificare varie opzioni su come deve essere eseguito il comando, ad esempio se sollevare un’eccezione in caso di fallimento.
Se ti interessa approfondire le infinite possibilità di automazione da riga di comando con Python, dai un’occhiata al nostro corso Command Line Automation in Python. In questo corso imparerai a scrivere codice di automazione che esplora un filesystem, cerca file che seguono un certo pattern e determina se i file sono duplicati in uno dei numerosi casi. Al termine del corso, sarai in grado di gestire e interagire con i processi Unix e di automatizzare una varietà di attività di routine del file system.
Potenzia le competenze in Python del tuo team con DataCamp for Business
Se tu o il tuo team volete migliorare le competenze in Python e nell’automazione da riga di comando, prendi in considerazione DataCamp for Business. DataCamp offre soluzioni di apprendimento su misura per team di tutte le dimensioni, aiutando le aziende a restare al passo in un panorama tecnologico in rapida evoluzione. Con DataCamp for Business puoi far crescere le competenze del tuo team con corsi e percorsi personalizzati pensati per sviluppare esperienza in Python, automazione e altri strumenti essenziali della data science. Che tu sia una startup o un’impresa, DataCamp for Business fornisce risorse e flessibilità per raggiungere gli obiettivi formativi del tuo team. Richiedi una demo oggi per saperne di più.
Domande frequenti su Python Subprocess
Qual è la differenza tra subprocess.call() e subprocess.run()?
subprocess.call() è una funzione che esegue un comando e attende che termini, restituendo il codice di ritorno del comando. subprocess.run() è una funzione più potente che ti permette di eseguire un comando, catturarne l’output e specificare varie opzioni su come deve essere eseguito, ad esempio se sollevare un’eccezione in caso di fallimento.
Come posso eseguire un comando e catturarne l’output in Python usando subprocess?
Puoi usare la funzione subprocess.run() per eseguire un comando e catturarne l’output in un’unica chiamata. Ad esempio, il seguente codice esegue il comando ls e ne cattura l’output nella variabile result:
import subprocess
result = subprocess.run(["ls"], stdout=subprocess.PIPE)
print(result.stdout.decode())
Come posso passare variabili come argomenti a un comando in un sottoprocesso?
Puoi passare variabili come argomenti a un comando nel sottoprocesso includendole nella lista passata alle funzioni subprocess.run() o subprocess.Popen(). Ad esempio, il seguente codice esegue il comando echo e passa il valore della variabile message come argomento:
import subprocess
message = "Hello, World!"
subprocess.run(["echo", message])
Come posso reindirizzare l’output di un comando su un file usando subprocess?
Puoi reindirizzare l’output di un comando su un file usando l’operatore > nel comando. Ad esempio, il seguente codice esegue il comando ls e ne reindirizza l’output su un file chiamato ls.txt:
import subprocess
subprocess.run("ls > ls.txt", shell=True)Come posso eseguire un comando in background usando subprocess?
Puoi eseguire un comando in background impostando il parametro start_new_session su True quando crei un nuovo processo usando subprocess.Popen(). Questo creerà un nuovo gruppo di processi, consentendoti di eseguire il comando in background.
import subprocess
subprocess.Popen(["ls"], start_new_session=True)
Come posso controllare il codice di ritorno di un comando eseguito con subprocess?
Puoi controllare il codice di ritorno di un comando accedendo all’attributo returncode dell’oggetto subprocess.CompletedProcess restituito da subprocess.run(). Ad esempio, il seguente codice esegue il comando ls e ne controlla il codice di ritorno:
import subprocess
result = subprocess.run(["ls"])
if result.returncode == 0:
print("Command ran successfully")
else:
print("Command failed with error code", result.returncode)
Come posso passare variabili d’ambiente a un comando eseguito con subprocess?
Puoi passare variabili d’ambiente a un comando includendole in un dizionario e passando quel dizionario come parametro env quando crei un nuovo processo usando subprocess.Popen() o subprocess.run(). Ad esempio, il seguente codice imposta la variabile d’ambiente TEST_VAR ed esegue il comando printenv:
import subprocess
env = {'TEST_VAR': 'test_value'}
subprocess.run(["printenv", "TEST_VAR"], env=env)
