1. Cos’è il modulo subprocess di Python?
Panoramica
Il modulo subprocess in Python è uno strumento potente per eseguire comandi di sistema e programmi esterni all’interno di Python. Utilizzando questo modulo, è possibile gestire l’input/output standard e i processi, rendendo facile l’integrazione di programmi esterni con script Python. Fornisce un modo più sicuro e flessibile per controllare i processi rispetto ai moduli tradizionali os.system() o commands.
Principali Casi d’Uso
- Esecuzione di comandi shell : Eseguire comandi di sistema semplici.
- Gestione dei processi : Eseguire programmi esterni e reindirizzare l’input/output standard.
- Elaborazione asincrona : Gestire attività a lungo termine e esecuzione parallela.
2. Utilizzo Base: subprocess.run()
Utilizzo Base
La funzione subprocess.run() consente di eseguire comandi di sistema all’interno di Python in modo semplice. Ad esempio, per elencare i file in una directory, è possibile utilizzare il seguente codice:
import subprocess
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
print(result.stdout)
Questo codice esegue il comando ls -l, cattura la sua uscita in stdout e la elabora all’interno di Python. L’opzione capture_output=True cattura l’output standard, e text=True garantisce che il risultato sia gestito come stringa.
Gestione degli Errori
Quando si utilizza subprocess.run(), è possibile recuperare i messaggi di errore utilizzando stderr se il comando fallisce. Inoltre, è possibile verificare il successo dell’esecuzione con returncode.
result = subprocess.run(['ls', 'nonexistentfile'], capture_output=True, text=True)
if result.returncode != 0:
print(f"Error: {result.stderr}")
In questo esempio, se viene specificato un file inesistente, verrà visualizzato un messaggio di errore tramite l’errore standard.

3. Esecuzione Asincrona: subprocess.Popen()
Elaborazione Asincrona con Popen
Poiché subprocess.run() è un’operazione sincrona, il programma Python non può procedere al passaggio successivo fino al completamento dell’esecuzione del comando. Tuttavia, utilizzando subprocess.Popen(), è possibile eseguire processi in modo asincrono e eseguire altre attività contemporaneamente.
import subprocess
proc = subprocess.Popen(['sleep', '5'], stdout=subprocess.PIPE)
print("Process started")
proc.wait()
print("Process completed")
In questo codice, il comando sleep 5 viene eseguito in modo asincrono, consentendo ad altre attività di procedere mentre è in esecuzione.
Controllo dell’Input e Output Standard
Con Popen, è possibile controllare con precisione il reindirizzamento dell’input e output standard. Ad esempio, il seguente codice legge i dati da un file, li elabora con il comando cat e scrive il risultato in un altro file.
with open('input.txt', 'r') as infile, open('output.txt', 'w') as outfile:
proc = subprocess.Popen(['cat'], stdin=infile, stdout=outfile)
proc.wait()
Questo consente di reindirizzare l’input e output standard dei comandi esterni a file per l’elaborazione.
4. Casi d’Uso: Script di Automazione
Backup dei File
Il modulo subprocess è altamente utile per automatizzare attività di gestione del sistema e operazioni periodiche. Ad esempio, lo script seguente copia automaticamente i file in una directory di backup:
import subprocess
files_to_backup = ['file1.txt', 'file2.txt', 'file3.txt']
backup_dir = '/backup/directory/'
for file in files_to_backup:
subprocess.run(['cp', file, backup_dir])
Questo script copia i file specificati in una cartella di backup. Creare script semplici come questo può aiutare ad automatizzare attività di backup di routine.
Utilizzo nei Pipeline CI/CD
Il modulo subprocess è comunemente utilizzato anche negli ambienti di Integrazione Continua (CI) e Distribuzione Continua (CD). Può essere incorporato in pipeline di automazione per eseguire script di test e gestire processi di distribuzione. Ad esempio, può essere utilizzato per eseguire automaticamente script di test e procedere al passaggio successivo solo se i test passano.

5. Sicurezza e Migliori Pratiche
Rischi di shell=True
L’opzione shell=True viene utilizzata per eseguire i comandi tramite la shell, ma comporta dei rischi di sicurezza. In particolare, quando si passa input esterno direttamente, c’è il pericolo di attacchi di injection nella shell. L’uso di shell=False riduce questo rischio.
import subprocess
# Recommended usage (safe)
subprocess.run(['ls', '-l'])
# shell=True (use with caution)
subprocess.run('ls -l', shell=True)
Compatibilità multipiattaforma
I comandi di sistema possono variare tra i diversi sistemi operativi. È possibile utilizzare il modulo platform di Python per determinare il SO e cambiare i comandi di conseguenza.
import platform
import subprocess
if platform.system() == "Windows":
subprocess.run(['dir'], shell=True)
else:
subprocess.run(['ls', '-l'])
6. Risoluzione dei problemi e debug
Errori comuni e soluzioni
Quando si utilizza subprocess, errori come “file non trovato” o “permesso negato” sono comuni. Questi possono essere catturati usando stderr e si può controllare returncode per ottenere dettagli sull’errore.
Suggerimenti per il debug
L’opzione check=True solleva un’eccezione se il comando fallisce, aiutoti a rilevare i problemi in anticipo. Catturare l’output standard e i messaggi di errore per il logging rende anche il debug più semplice.
import subprocess
try:
result = subprocess.run(['ls', '-l'], check=True, capture_output=True, text=True)
print(result.stdout)
except subprocess.CalledProcessError as e:
print(f"An error occurred: {e}")
7. Elaborazione asincrona con asyncio
Elaborazione asincrona usando asyncio
Utilizzando asyncio, è possibile integrare subprocess con l’elaborazione asincrona, consentendo a più processi di essere eseguiti in parallelo. L’esempio seguente esegue il comando ls in modo asincrono e ne cattura l’output.
import asyncio
import subprocess
async def run_command():
proc = await asyncio.create_subprocess_exec('ls', '-l',
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
if stdout:
print(f'[stdout]n{stdout.decode()}')
if stderr:
print(f'[stderr]n{stderr.decode()}')
asyncio.run(run_command())
Questo codice esegue il comando in modo asincrono e elabora l’output standard e l’output di errore. L’uso di asyncio consente una gestione efficiente dei task asincroni.




![[Guida completa al costrutto with di Python] Semplificare la gestione delle risorse](https://www.python.digibeatrix.com/wp-content/uploads/2024/09/a899e1b4cda16b8a13042ca3ec2153b5-375x375.webp)
