Kilka praktycznych zasad subprocess.
- Nigdy nie używaj
shell=True. Niepotrzebnie wywołuje dodatkowy proces powłoki, aby wywołać program.
- Podczas wywoływania procesów argumenty są przekazywane jako listy.
sys.argvw Pythonie jest lista, a więc jest argvw C. Więc przekazać listę do Popen, aby zadzwonić do podprocesów, a nie ciąg.
- Nie przekierowuj
stderrdo a, PIPEgdy go nie czytasz.
- Nie przekierowuj,
stdinkiedy do niego nie piszesz.
Przykład:
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())
To powiedziawszy, jest prawdopodobne, że rsync buforuje swoje dane wyjściowe, gdy wykryje, że jest podłączony do potoku zamiast terminala. Jest to zachowanie domyślne - po podłączeniu do potoku programy muszą jawnie opróżniać standardowe wyjście, aby uzyskać wyniki w czasie rzeczywistym, w przeciwnym razie standardowa biblioteka C będzie buforować.
Aby to sprawdzić, spróbuj zamiast tego uruchomić:
cmd = [sys.executable, 'test_out.py']
i utwórz test_out.pyplik z zawartością:
import sys
import time
print ("Hello")
sys.stdout.flush()
time.sleep(10)
print ("World")
Wykonanie tego podprocesu powinno dać ci „Hello” i odczekać 10 sekund przed podaniem „World”. Jeśli tak się stanie z powyższym kodem Pythona, a nie z rsync, oznacza to, że rsyncsam buforuje dane wyjściowe, więc nie masz szczęścia.
Rozwiązaniem byłoby podłączenie się bezpośrednio do pty, używając czegoś takiego jak pexpect.