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.argv
w Pythonie jest lista, a więc jest argv
w C. Więc przekazać listę do Popen
, aby zadzwonić do podprocesów, a nie ciąg.
- Nie przekierowuj
stderr
do a, PIPE
gdy go nie czytasz.
- Nie przekierowuj,
stdin
kiedy 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.py
plik 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 rsync
sam 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
.