Alcune regole pratiche per subprocess
.
- Non usare mai
shell=True
. Invoca inutilmente un processo di shell aggiuntivo per chiamare il programma.
- Quando si chiamano processi, gli argomenti vengono passati come elenchi.
sys.argv
in python è una lista, e così è argv
in C. Quindi passi una lista aPopen
per chiamare sottoprocessi, non una stringa.
- Non reindirizzare
stderr
a un filePIPE
quando non lo stai leggendo.
- Non reindirizzare
stdin
quando non ci scrivi.
Esempio:
import subprocess, time, os, sys
cmd = ["rsync.exe", "-vaz", "-P", "source/" ,"dest/"]
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
for line in iter(p.stdout.readline, b''):
print(">>> " + line.rstrip())
Detto questo, è probabile che rsync bufferizzi il suo output quando rileva che è connesso a una pipe invece che a un terminale. Questo è il comportamento predefinito: quando si è connessi a una pipe, i programmi devono svuotare esplicitamente lo stdout per ottenere risultati in tempo reale, altrimenti la libreria C standard verrà bufferizzata.
Per verificarlo, prova a eseguire questo invece:
cmd = [sys.executable, 'test_out.py']
e crea un test_out.py
file con il contenuto:
import sys
import time
print ("Hello")
sys.stdout.flush()
time.sleep(10)
print ("World")
L'esecuzione di quel sottoprocesso dovrebbe darti "Hello" e attendere 10 secondi prima di dare "World". Se ciò accade con il codice python sopra e non con rsync
, significa che esso rsync
stesso esegue il buffering dell'output, quindi sei sfortunato.
Una soluzione sarebbe connettersi direttamente a un pty
, usando qualcosa di simile pexpect
.