Polecenie popen w Pythonie. Poczekaj, aż polecenie zostanie zakończone

79

Mam skrypt, w którym uruchamiam się za pomocą polecenia powłoki. Problem polega na tym, że skrypt nie czeka, aż polecenie popen zakończy się i od razu kontynuuje działanie.

om_points = os.popen(command, "w")
.....

Jak mogę powiedzieć mojemu skryptowi Pythona, aby zaczekał, aż polecenie powłoki zakończy się?

michele
źródło

Odpowiedzi:

112

W zależności od tego, jak chcesz pracować ze swoim skryptem, masz dwie opcje. Jeśli chcesz, aby polecenia blokowały się i nie robiły nic podczas ich wykonywania, możesz po prostu użyć subprocess.call.

#start and block until done
subprocess.call([data["om_points"], ">", diz['d']+"/points.xml"])

Jeśli chcesz robić rzeczy podczas wykonywania lub podawać rzeczy stdin, możesz użyć communicatepo popenwywołaniu.

#start and process things, then wait
p = subprocess.Popen([data["om_points"], ">", diz['d']+"/points.xml"])
print "Happens while running"
p.communicate() #now wait plus that you can send commands to process

Jak stwierdzono w dokumentacji, waitmoże zakleszczać się, więc komunikacja jest wskazana.

unholysampler
źródło
Sprawdź dokumentację na subprocess.call
thornomad
Chociaż podproces jest preferowany w wielu odpowiedziach, nie radzi sobie zbyt dobrze z przestrzenią i kwotami w poleceniu. Powyższa odpowiedź nie rozwiązuje bezpośrednio pytania os.popen.
Chang,
podproces może wynosić do 2x wolniej niż systemu os - bugs.python.org/issue37790
MonsieurBeilto
subprocess.run()został dodany w Pythonie 3.5 i jest „Zalecanym podejściem do wywoływania podprocesów”
LoMaPh
29

Możesz użyć, subprocessaby to osiągnąć.

import subprocess

#This command could have multiple commands separated by a new line \n
some_command = "export PATH=$PATH://server.sample.mo/app/bin \n customupload abc.txt"

p = subprocess.Popen(some_command, stdout=subprocess.PIPE, shell=True)

(output, err) = p.communicate()  

#This makes the wait possible
p_status = p.wait()

#This will give you the output of the command being executed
print "Command output: " + output
Kamień probierczy
źródło
podproces może wynosić do 2x wolniej niż systemu os - bugs.python.org/issue37790
MonsieurBeilto
12

Wymuś, popenaby nie kontynuować, dopóki wszystkie dane wyjściowe nie zostaną odczytane, wykonując:

os.popen(command).read()
Alberto
źródło
2
Nie jestem ekspertem od Pythona, ale wydaje się, że jest to najprostsze rozwiązanie, które wprowadza najmniej modyfikacji w oryginalnym kodzie. Czy jest jakiś powód, dla którego nie byłoby to dobre rozwiązanie?
jdmcnair
7

Niech polecenie, które próbujesz przekazać, będzie

os.system('x')

następnie zamieniasz to w oświadczenie

t = os.system('x')

teraz python będzie czekał na dane wyjściowe z wiersza poleceń, aby można je było przypisać do zmiennej t.

Chidhambararajan NRM
źródło
4

To, czego szukasz, to waitmetoda.

Olivier Verdier
źródło
Ale jeśli wpiszę: om_points = os.popen (data ["om_points"] + ">" + diz ['d'] + "/ points.xml", "w"). Wait () Otrzymuję ten błąd: Traceback (ostatnie połączenie ostatnie): File "./model_job.py", linia 77, w <module> om_points = os.popen (data ["om_points"] + ">" + diz ['d'] + "/ points .xml "," w "). wait () AttributeError: 'file' obiekt nie ma atrybutu 'wait' Na czym polega problem? Dzięki jeszcze raz.
michele
12
Nie kliknąłeś podanego przeze mnie łącza. waitjest metodą subprocessklasy.
Olivier Verdier
1
wait może zakleszczać się, jeśli proces zapisuje na standardowe wyjście i nikt go nie czyta
ansgri
podproces może wynosić do 2x wolniej niż systemu os - bugs.python.org/issue37790
MonsieurBeilto
2

wait () działa dobrze dla mnie. Podprocesy p1, p2 i p3 są wykonywane jednocześnie. Dlatego wszystkie procesy są wykonywane po 3 sekundach.

import subprocess

processes = []

p1 = subprocess.Popen("sleep 3", stdout=subprocess.PIPE, shell=True)
p2 = subprocess.Popen("sleep 3", stdout=subprocess.PIPE, shell=True)
p3 = subprocess.Popen("sleep 3", stdout=subprocess.PIPE, shell=True)

processes.append(p1)
processes.append(p2)
processes.append(p3)

for p in processes:
    if p.wait() != 0:
        print("There was an error")

print("all processed finished")
simibac
źródło
podproces może wynosić do 2x wolniej niż systemu os - bugs.python.org/issue37790
MonsieurBeilto
0

Myślę, że process.communicate () byłby odpowiedni do wyjścia o małym rozmiarze. W przypadku większej wydajności nie byłoby to najlepsze podejście.

Barsha Lamichhane
źródło