wyjście na żywo z polecenia podprocess

Używam skryptu Pythona jako Sterownika kodu hydrodynamicznego. Kiedy przychodzi czas na uruchomienie symulacji, używam subprocess.Popen do uruchomienia kodu, zbieram dane wyjściowe ze stdout i stderr do subprocess.PIPE - - - Następnie mogę wydrukować (i zapisać do pliku dziennika) informacje wyjściowe i sprawdzić, czy nie ma błędów. Problem w tym, że nie mam pojęcia, jak postępuje kod. Jeśli uruchamiam go bezpośrednio z linii poleceń, to daje mi wyjście o tym, co iteracja jego w, o której godzinie, co następnym krokiem jest, itd.

Czy istnieje sposób, aby zarówno przechowywać dane wyjściowe (do rejestrowania i sprawdzania błędów), jak i produkować wyjście strumieniowe na żywo?

Odpowiedni fragment mojego kodu:

ret_val = subprocess.Popen( run_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True )
output, errors = ret_val.communicate()
log_file.write(output)
print output
if( ret_val.returncode ):
    print "RUN failed\n\n%s\n\n" % (errors)
    success = False

if( errors ): log_file.write("\n\n%s\n\n" % errors)

Początkowo przepuszczałem run_command przez tee tak, że kopia poszła bezpośrednio do pliku dziennika, a strumień nadal wypływa bezpośrednio do terminala -- ale w ten sposób nie mogę przechowywać żadnych błędów (według mojej wiedzy).


Edit:

Rozwiązanie tymczasowe:

ret_val = subprocess.Popen( run_command, stdout=log_file, stderr=subprocess.PIPE, shell=True )
while not ret_val.poll():
    log_file.flush()

Wtedy, w kolejny terminal, Uruchom tail -f log.txt (s. t. log_file = 'log.txt').

Author: DilithiumMatrix, 2013-08-24

12 answers

Można to zrobić na dwa sposoby, tworząc iterator z funkcji read lub readline i wykonując:

import subprocess
import sys
with open('test.log', 'w') as f:
    process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
    for c in iter(lambda: process.stdout.read(1), ''):  # replace '' with b'' for Python 3
        sys.stdout.write(c)
        f.write(c)

Lub

import subprocess
import sys
with open('test.log', 'w') as f:
    process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
    for line in iter(process.stdout.readline, ''):  # replace '' with b'' for Python 3
        sys.stdout.write(line)
        f.write(line)

Lub możesz utworzyć plik reader i writer. Przekaż writer do Popen i odczytaj z reader

import io
import time
import subprocess
import sys

filename = 'test.log'
with io.open(filename, 'wb') as writer, io.open(filename, 'rb', 1) as reader:
    process = subprocess.Popen(command, stdout=writer)
    while process.poll() is None:
        sys.stdout.write(reader.read())
        time.sleep(0.5)
    # Read the remaining
    sys.stdout.write(reader.read())

W ten sposób dane będą zapisywane zarówno w test.log, jak i na standardowym wyjściu.

Jedyną zaletą podejścia do plików jest to, że Twój kod nie blokuje się. Więc w międzyczasie możesz robić, co chcesz. i czytać kiedy chcesz z reader w sposób nieblokujący. Kiedy używasz PIPE, read i readline funkcje będą blokować, dopóki jeden znak nie zostanie zapisany do rury lub linia zostanie zapisana odpowiednio do rury.

 113
Author: Viktor Kerkez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-18 04:55:33

Streszczenie (lub wersja" TL;dr"): jest łatwo, gdy jest co najwyżej jedna subprocess.PIPE, w przeciwnym razie jest ciężko.

To może być czas, aby wyjaśnić trochę o tym, jak subprocess.Popen robi swoje rzeczy.

(Zastrzeżenie: to jest dla Pythona 2.x, chociaż 3.x jest podobny; i jestem dość niewyraźny w wariancie Windows. Rozumiem rzeczy POSIX znacznie lepiej.)

Funkcja Popen musi obsługiwać od zera do trzech strumieni We/Wy, nieco jednocześnie. Są one oznaczone stdin, stdout, i stderr jako to co zwykle.

Możesz podać:

  • None, wskazując, że nie chcesz przekierowywać strumienia. Odziedziczy je jak zwykle. Zauważ, że przynajmniej w systemach POSIX, nie oznacza to, że będzie używać Pythona sys.stdout, tylko Pythona actual stdout; patrz demo na końcu.
  • An int wartość. Jest to "surowy" deskryptor pliku (przynajmniej w POSIX). (Uwaga: PIPE i STDOUT są wewnętrznie int, ale są" niemożliwymi " deskryptorami, -1 i -2.)
  • strumień-właściwie każdy obiekt z metodą fileno. Popen znajdzie deskryptor dla tego strumienia, używając stream.fileno(), a następnie postępować tak, jak dla wartości int.
  • subprocess.PIPE, wskazując, że Python powinien utworzyć rurę.
  • subprocess.STDOUT (tylko dla stderr): powiedz Pythonowi, aby używał tego samego deskryptora, co dla stdout. Ma to sens tylko wtedy, gdy podałeś (nie-None) wartość dla stdout, a nawet wtedy, jest ona potrzebna tylko , jeśli Ustawiłeś stdout=subprocess.PIPE. (W przeciwnym razie można po prostu podaj ten sam argument, który podałeś dla stdout, np. Popen(..., stdout=stream, stderr=stream).)

Najprostsze przypadki (bez rur)

Jeśli nic nie przekierujesz (pozostaw wszystkie trzy jako domyślną wartość None lub podaj jawną None), Pipe ma to dość proste. Musi tylko wyłączyć podproces i pozwolić mu działać. Albo, jeśli przekierujesz do Nie - PIPE - an int lub strumienia fileno() - nadal jest to łatwe, ponieważ system operacyjny wykonuje całą pracę. Pythona wystarczy wyłączyć podproces, łącząc jego stdin, stdout i / lub stderr do dostarczonych deskryptorów plików.

Sprawa still-easy: jedna rura

Jeśli przekierujesz tylko jeden strumień, Pipe nadal ma rzeczy dość łatwe. Wybierzmy jeden strumień na raz i oglądajmy.

Załóżmy, że chcesz podać jakieś stdin, ale pozwól stdout i {[11] } przejść bez przekierowania lub przejść do deskryptora pliku. Jako proces macierzysty, Twój program w Pythonie musi po prostu użyć write(), aby wysłać dane w dół potoku. Możesz to zrobić sam, np.:

proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
proc.stdin.write('here, have some data\n') # etc

Lub możesz przekazać dane stdin do proc.communicate(), które następnie wykonuje stdin.write pokazane powyżej. Nie ma wyjścia, więc communicate() ma tylko jedno prawdziwe zadanie: zamyka rurę za Ciebie. (Jeśli nie zadzwonisz proc.communicate(), musisz zadzwonić proc.stdin.close(), aby zamknąć rurę, aby podproces wiedział, że nie ma więcej danych.)

Załóżmy, że chcesz schwytać stdout ale zostaw stdin i stderr w spokoju. Ponownie, to proste: wystarczy zadzwonić proc.stdout.read() (lub równoważne), aż nie ma większa wydajność. Ponieważ proc.stdout() jest normalnym strumieniem We/Wy Pythona, możesz użyć na nim wszystkich normalnych konstrukcji, takich jak:

for line in proc.stdout:

Lub, ponownie, możesz użyć proc.communicate(), który po prostu robi read() za Ciebie.

Jeśli chcesz przechwytywać tylko stderr, działa to tak samo jak w przypadku stdout.

Jest jeszcze jedna sztuczka, zanim zrobi się ciężko. Załóżmy, że chcesz przechwycić stdout, a także przechwycić stderr, ale na tej samej rurze co stdout:
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

W tym przypadku, subprocess "oszukuje"! Cóż, musi to zrobić, więc nie jest to oszustwo: uruchamia podproces zarówno ze swoim stdout, jak i ze stderr skierowanym do (pojedynczego) deskryptora potoku, który przekierowuje z powrotem do jego macierzystego (Pythona) procesu. Po stronie nadrzędnej znajduje się ponownie tylko jeden deskryptor rury do odczytu wyjścia. Wszystkie wyjścia "stderr" pojawiają się w proc.stdout, a jeśli wywołasz proc.communicate(), wynikiem stderr (druga wartość krotki) będzie None, a nie Łańcuch znaków.

Twarde przypadki: dwa lub więcej rury

Problemy pojawiają się, gdy chcesz użyć przynajmniej dwóch rur. W rzeczywistości kod subprocess ma ten bit:

def communicate(self, input=None):
    ...
    # Optimization: If we are only using one pipe, or no pipe at
    # all, using select() or threads is unnecessary.
    if [self.stdin, self.stdout, self.stderr].count(None) >= 2:

Ale, niestety, tutaj zrobiliśmy co najmniej dwie, a może trzy, różne rury, więc count(None) zwraca albo 1, albo 0. Musimy robić rzeczy w trudny sposób.

W systemie Windows, To używa {[64] } do gromadzenia wyników dla self.stdout i self.stderr, i sprawia, że wątek nadrzędny dostarcza self.stdin dane wejściowe (a następnie zamyka przewód).

Na POSIX, to używa poll, jeśli jest dostępny, w przeciwnym razie select, do gromadzenia danych wyjściowych i dostarczania wejścia stdin. Wszystko to działa w (pojedynczym) procesie rodzica/wątku.

Threads lub poll / select są potrzebne tutaj, aby uniknąć impasu. Załóżmy na przykład, że przekierowaliśmy wszystkie trzy strumienie do trzech oddzielnych rur. Załóżmy ponadto, że istnieje mały limit ilości danych, które mogą być włożone do rury, zanim proces zapisu zostanie zawieszony, czekając na proces odczytu, aby" wyczyścić " rurę z drugi koniec. Ustawmy ten mały limit na jeden bajt, tylko dla ilustracji. (W rzeczywistości tak to działa, z tym wyjątkiem, że limit jest znacznie większy niż jeden bajt.)

Jeśli proces macierzysty (Python) próbuje zapisać kilka bajtów-powiedzmy, 'go\n' do proc.stdin, pierwszy bajt wchodzi do środka, a drugi powoduje zawieszenie procesu Pythona, czekając na podproces odczytujący pierwszy bajt, opróżniając rurę.

Tymczasem Załóżmy, że podproces decyduje się wydrukować przyjazną "Halo! Nie panikuj!"pozdrawiam. W przeciwieństwie do tego, że nie jest on w stanie odczytać kodu, nie jest on w stanie odczytać kodu źródłowego.

Teraz utknęliśmy: proces Pythona śpi, czeka na zakończenie mówiąc "go", a podproces również śpi, czeka na zakończenie mówiąc " Hello! Nie panikuj!".

Kod subprocess.Popen unika tego problemu z threading-or-select / poll. Gdy bajty mogą przejść przez rury, idą. Kiedy nie mogą, tylko wątek (nie cały proces) musi być uśpiony-lub, w przypadku select / poll, proces Pythona czeka jednocześnie na "can write" lub "data available", zapisuje na stdin procesu tylko wtedy, gdy jest miejsce i odczytuje jego stdout i/lub stderr tylko wtedy, gdy dane są gotowe. Kod proc.communicate() (w rzeczywistości _communicate, w którym obsługiwane są przypadki hairy) zwraca po wysłaniu wszystkich danych stdin (o ile istnieją) i zgromadzeniu wszystkich danych stdout i / lub stderr.

Jeśli chcesz przeczytać zarówno stdout i stderr na dwóch różnych rurach (niezależnie od jakiegokolwiek przekierowania stdin), musisz również uniknąć impasu. Scenariusz impasu jest tutaj inny-występuje, gdy podproces pisze coś długiego do stderr podczas pobierania danych z stdout, lub odwrotnie-ale nadal tam jest.


Demo

Obiecałem, że zademonstruję, że, bez przekierowania, Python subprocesses zapisuje do bazowego stdout, a nie sys.stdout. Oto kod:

from cStringIO import StringIO
import os
import subprocess
import sys

def show1():
    print 'start show1'
    save = sys.stdout
    sys.stdout = StringIO()
    print 'sys.stdout being buffered'
    proc = subprocess.Popen(['echo', 'hello'])
    proc.wait()
    in_stdout = sys.stdout.getvalue()
    sys.stdout = save
    print 'in buffer:', in_stdout

def show2():
    print 'start show2'
    save = sys.stdout
    sys.stdout = open(os.devnull, 'w')
    print 'after redirect sys.stdout'
    proc = subprocess.Popen(['echo', 'hello'])
    proc.wait()
    sys.stdout = save

show1()
show2()

Kiedy przebieg:

$ python out.py
start show1
hello
in buffer: sys.stdout being buffered

start show2
hello

Zauważ, że pierwsza procedura zakończy się niepowodzeniem, jeśli dodasz stdout=sys.stdout, ponieważ StringIO obiekt nie ma fileno. Drugi pomija hello, jeśli dodasz stdout=sys.stdout, ponieważ sys.stdout zostało przekierowane na os.devnull.

(jeśli przekierujesz plik Pythona-deskryptor-1, podproces podąży za tym przekierowaniem. Wywołanie open(os.devnull, 'w') wytwarza strumień, którego {[36] } jest większy niż 2.)

 69
Author: torek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-24 20:51:33

Jeśli możesz korzystać z bibliotek innych firm, możesz użyć czegoś takiego jak sarge (ujawnienie: jestem jego opiekunem). Biblioteka ta umożliwia nieblokujący dostęp do strumieni wyjściowych z podprocesów-jest warstwowa nad modułem subprocess.

 10
Author: Vinay Sajip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-24 16:00:14

Możemy również użyć domyślnego iteratora pliku do odczytu stdout zamiast używać ITER construct z readline ().

import subprocess
import sys
process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
for line in process.stdout:
    sys.stdout.write(line)
 6
Author: Jughead,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-13 01:37:08

Dobrym, ale" ciężkim " rozwiązaniem jest użycie Twisted-patrz dno.

Jeśli chcesz żyć tylko ze stdout coś w tym stylu powinno działać:

import subprocess
import sys
popenobj = subprocess.Popen(["ls", "-Rl"], stdout=subprocess.PIPE)
while not popenobj.poll():
   stdoutdata = popenobj.stdout.readline()
   if stdoutdata:
      sys.stdout.write(stdoutdata)
   else:
      break
print "Return code", popenobj.returncode

(Jeśli używasz read (), to próbuje odczytać cały "plik", który nie jest użyteczny, to co naprawdę możemy tu wykorzystać to coś, co odczytuje wszystkie dane znajdujące się w potoku)

Można też próbować podejść do tego z threadingiem, np.:

import subprocess
import sys
import threading

popenobj = subprocess.Popen("ls", stdout=subprocess.PIPE, shell=True)

def stdoutprocess(o):
   while True:
      stdoutdata = o.stdout.readline()
      if stdoutdata:
         sys.stdout.write(stdoutdata)
      else:
         break

t = threading.Thread(target=stdoutprocess, args=(popenobj,))
t.start()
popenobj.wait()
t.join()
print "Return code", popenobj.returncode

Teraz możemy potencjalnie dodać stderr również przez posiadające dwie nitki.

Zauważ jednak, że podprocesowe dokumenty zniechęcają do bezpośredniego korzystania z tych plików i zalecają użycie communicate() (głównie dotyczy to blokad, które moim zdaniem nie są problemem powyżej), a rozwiązania są trochę klunky, więc naprawdę wydaje się, że Moduł podprocesowy nie jest do końca odpowiedni do zadania (Zobacz także: http://www.python.org/dev/peps/pep-3145 / ) i musimy spojrzeć na coś innego.

Bardziej zaangażowanym rozwiązaniem jest użycie Twisted jako pokazane tutaj: https://twistedmatrix.com/documents/11.1.0/core/howto/process.html

Sposób, w jaki robisz to za pomocą Twisted, polega na utworzeniu procesu za pomocą reactor.spawnprocess() i dostarczeniu ProcessProtocol, który następnie przetwarza wyjście asynchronicznie. Pokręcony przykładowy kod Pythona jest tutaj: https://twistedmatrix.com/documents/11.1.0/core/howto/listings/process/process.py

 2
Author: Guy Sirton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-24 21:35:15

Wygląda na to, że wyjście buforowane liniowo będzie działać dla Ciebie, w takim przypadku może pasować coś podobnego do następującego. (Zastrzeżenie: to nieprzetestowane.) To da tylko stdout podprocesu w czasie rzeczywistym. Jeśli chcesz mieć zarówno stderr jak i stdout w czasie rzeczywistym, musisz zrobić coś bardziej skomplikowanego za pomocą select.

proc = subprocess.Popen(run_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
while proc.poll() is None:
    line = proc.stdout.readline()
    print line
    log_file.write(line + '\n')
# Might still be data on stdout at this point.  Grab any
# remainder.
for line in proc.stdout.read().split('\n'):
    print line
    log_file.write(line + '\n')
# Do whatever you want with proc.stderr here...
 1
Author: Alp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-24 19:21:35

Dlaczego nie ustawić stdout bezpośrednio na sys.stdout? I jeśli chcesz również wypisać do dziennika, możesz po prostu nadpisać metodę zapisu f.

import sys
import subprocess

class SuperFile(open.__class__):

    def write(self, data):
        sys.stdout.write(data)
        super(SuperFile, self).write(data)

f = SuperFile("log.txt","w+")       
process = subprocess.Popen(command, stdout=f, stderr=f)
 0
Author: xaav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-04 19:54:16

Oto Klasa, której używam w jednym z moich projektów. Przekierowuje wyjście podprocesu do dziennika. Na początku próbowałem po prostu nadpisać metodę write, ale to nie działa, ponieważ podproces nigdy jej nie wywoła (przekierowanie odbywa się na poziomie filedescriptor). Więc używam własnej rury, podobnie jak to się robi w podproces-module. Zaletą tego rozwiązania jest hermetyzacja całej logiki logowania/drukowania w adapterze i można po prostu przekazać instancje rejestratora do Popen: subprocess.Popen("/path/to/binary", stderr = LogAdapter("foo"))

class LogAdapter(threading.Thread):

    def __init__(self, logname, level = logging.INFO):
        super().__init__()
        self.log = logging.getLogger(logname)
        self.readpipe, self.writepipe = os.pipe()

        logFunctions = {
            logging.DEBUG: self.log.debug,
            logging.INFO: self.log.info,
            logging.WARN: self.log.warn,
            logging.ERROR: self.log.warn,
        }

        try:
            self.logFunction = logFunctions[level]
        except KeyError:
            self.logFunction = self.log.info

    def fileno(self):
        #when fileno is called this indicates the subprocess is about to fork => start thread
        self.start()
        return self.writepipe

    def finished(self):
       """If the write-filedescriptor is not closed this thread will
       prevent the whole program from exiting. You can use this method
       to clean up after the subprocess has terminated."""
       os.close(self.writepipe)

    def run(self):
        inputFile = os.fdopen(self.readpipe)

        while True:
            line = inputFile.readline()

            if len(line) == 0:
                #no new data was added
                break

            self.logFunction(line.strip())

Jeśli nie potrzebujesz logowania, ale po prostu chcesz użyć print(), możesz oczywiście usunąć duże części kodu i zachować klasę krótszą. Możesz również rozwinąć go za pomocą metody __enter__ i __exit__ i wywołać finished w __exit__, aby łatwo użyć go jako kontekstu.

 0
Author: t.animal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-21 14:31:26

Wszystkie powyższe rozwiązania nie powiodły się albo do oddzielenia wyjścia stderr i stdout, (wiele rur) lub zablokowane na zawsze, gdy bufor rur OS był pełny, co dzieje się, gdy polecenie uruchamiasz wyjścia zbyt szybko (jest ostrzeżenie dla tego w Python poll() podręcznik podprocesu). Jedynym niezawodnym sposobem, jaki znalazłem, było select, ale jest to rozwiązanie wyłącznie posix:

import subprocess
import sys
import os
import select
# returns command exit status, stdout text, stderr text
# rtoutput: show realtime output while running
def run_script(cmd,rtoutput=0):
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    poller = select.poll()
    poller.register(p.stdout, select.POLLIN)
    poller.register(p.stderr, select.POLLIN)

    coutput=''
    cerror=''
    fdhup={}
    fdhup[p.stdout.fileno()]=0
    fdhup[p.stderr.fileno()]=0
    while sum(fdhup.values()) < len(fdhup):
        try:
            r = poller.poll(1)
        except select.error, err:
            if err.args[0] != EINTR:
                raise
            r=[]
        for fd, flags in r:
            if flags & (select.POLLIN | select.POLLPRI):
                c = os.read(fd, 1024)
                if rtoutput:
                    sys.stdout.write(c)
                    sys.stdout.flush()
                if fd == p.stderr.fileno():
                    cerror+=c
                else:
                    coutput+=c
            else:
                fdhup[fd]=1
    return p.poll(), coutput.strip(), cerror.strip()
 0
Author: sivann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-25 14:25:16

Oprócz wszystkich tych odpowiedzi, jedno proste podejście może być również następujące:

process = subprocess.Popen(your_command, stdout=subprocess.PIPE)

while process.stdout.readable():
    line = rstrm.readline()

    if not line:
        break

    print(line.strip())

Pętla przez czytelny strumień tak długo, jak jest czytelny i jeśli otrzyma pusty wynik, zatrzymaj go.

Kluczem jest to, że readline() zwraca linię (z {[2] } na końcu) tak długo, jak jest wyjście i jest puste, jeśli naprawdę jest na końcu.

Mam nadzieję, że to komuś pomoże.
 0
Author: kabirbaidhya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-30 07:32:01

Zaryzykuję tutaj i zaproponuję użycie check_call. Zgodnie z dokumentacją, uruchamia operację blokowania i pasuje do tego celu całkiem dobrze.

Uruchom polecenie z argumentami. Poczekaj na zakończenie. Jeśli zwracany kod to zero, a następnie return, w przeciwnym razie raise CalledProcessError. Obiekt CalledProcessError będzie miał kod powrotu w atrybut returncode.

cmd = "some_crazy_long_script.sh"
args = {
    'shell': True,
    'cwd': if_you_need_it
}

subprocess.check_call(cmd, **args)
 -2
Author: Debosmit Ray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-24 16:49:12
import sys
import subprocess

f = open("log.txt","w+")
process = subprocess.Popen(command, stdout=subprocess.PIPE)
for line in iter(process.stdout.readline, ''):
    sys.stdout.write(line)
    f.write(line.replace("\n",""))
f.close()
 -5
Author: sohom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-29 11:54:28