Guida completa al modulo subprocess di Python | Dalle basi all’avanzato

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.
Ad

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.

Ad
年収訴求

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.

Ad

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.

Ad
侍エンジニア塾

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'])
Ad

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}")
Ad

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.

Ad
RUNTEQ(ランテック)|超実戦型エンジニア育成スクール