Domanda

Ho un programma Python per Linux sembra quasi come questo:

import os
import time

process = os.popen("top").readlines()

time.sleep(1)

os.popen("killall top")

print process

il programma si blocca in questa linea:

process = os.popen("top").readlines()

e che avviene negli strumenti che mantengono aggiornamento Emissione come "Top"

i miei migliori prove:

import os
import time
import subprocess

process = subprocess.Popen('top')

time.sleep(2)

os.popen("killall top")

print process

ha funzionato meglio rispetto al primo (è kelled), ma restituisce:

<subprocess.Popen object at 0x97a50cc>

la seconda prova:

import os
import time
import subprocess

process = subprocess.Popen('top').readlines()

time.sleep(2)

os.popen("killall top")

print process

lo stesso del primo. E 'impiccato a causa di "readlines ()"

Il suo ritorno dovrebbe essere simile a questo:

top - 05:31:15 up 12:12,  5 users,  load average: 0.25, 0.14, 0.11
Tasks: 174 total,   2 running, 172 sleeping,   0 stopped,   0 zombie
Cpu(s):  9.3%us,  3.8%sy,  0.1%ni, 85.9%id,  0.9%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1992828k total,  1849456k used,   143372k free,   233048k buffers
Swap:  4602876k total,        0k used,  4602876k free,  1122780k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
31735 Barakat   20   0  246m  52m  20m S 19.4  2.7  13:54.91 totem              
 1907 root      20   0 91264  45m  15m S  1.9  2.3  38:54.14 Xorg               
 2138 Barakat   20   0 17356 5368 4284 S  1.9  0.3   3:00.15 at-spi-registry    
 2164 Barakat    9 -11  164m 7372 6252 S  1.9  0.4   2:54.58 pulseaudio         
 2394 Barakat   20   0 27212 9792 8256 S  1.9  0.5   6:01.48 multiload-apple    
 6498 Barakat   20   0 56364  30m  18m S  1.9  1.6   0:03.38 pyshell            
    1 root      20   0  2880 1416 1208 S  0.0  0.1   0:02.02 init               
    2 root      20   0     0    0    0 S  0.0  0.0   0:00.02 kthreadd           
    3 root      RT   0     0    0    0 S  0.0  0.0   0:00.12 migration/0        
    4 root      20   0     0    0    0 S  0.0  0.0   0:02.07 ksoftirqd/0        
    5 root      RT   0     0    0    0 S  0.0  0.0   0:00.00 watchdog/0         
    9 root      20   0     0    0    0 S  0.0  0.0   0:01.43 events/0           
   11 root      20   0     0    0    0 S  0.0  0.0   0:00.00 cpuset             
   12 root      20   0     0    0    0 S  0.0  0.0   0:00.02 khelper            
   13 root      20   0     0    0    0 S  0.0  0.0   0:00.00 netns              
   14 root      20   0     0    0    0 S  0.0  0.0   0:00.00 async/mgr          
   15 root      20   0     0    0    0 S  0.0  0.0   0:00.00 pm

e salvare nel "processo" variabile. Eventuali ho idea ragazzi, sono veramente bloccato ora?

È stato utile?

Soluzione

#!/usr/bin/env python
"""Start process; wait 2 seconds; kill the process; print all process output."""
import subprocess
import tempfile
import time

def main():
    # open temporary file (it automatically deleted when it is closed)
    #  `Popen` requires `f.fileno()` so `SpooledTemporaryFile` adds nothing here
    f = tempfile.TemporaryFile() 

    # start process, redirect stdout
    p = subprocess.Popen(["top"], stdout=f)

    # wait 2 seconds
    time.sleep(2)

    # kill process
    #NOTE: if it doesn't kill the process then `p.wait()` blocks forever
    p.terminate() 
    p.wait() # wait for the process to terminate otherwise the output is garbled

    # print saved output
    f.seek(0) # rewind to the beginning of the file
    print f.read(), 
    f.close()

if __name__=="__main__":
    main()

Tail-like Soluzioni che stampare solo la parte dell'uscita

Si potrebbe leggere l'uscita di processo in un altro thread e salvare il numero richiesto delle ultime righe in una coda:

import collections
import subprocess
import time
import threading

def read_output(process, append):
    for line in iter(process.stdout.readline, ""):
        append(line)

def main():
    # start process, redirect stdout
    process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)
    try:
        # save last `number_of_lines` lines of the process output
        number_of_lines = 200
        q = collections.deque(maxlen=number_of_lines) # atomic .append()
        t = threading.Thread(target=read_output, args=(process, q.append))
        t.daemon = True
        t.start()

        #
        time.sleep(2)
    finally:
        process.terminate() #NOTE: it doesn't ensure the process termination

    # print saved lines
    print ''.join(q)

if __name__=="__main__":
    main()

Questa variante richiede q.append() essere un'operazione atomica. In caso contrario, l'uscita potrebbe essere danneggiato.

signal.alarm() soluzione

Si potrebbe usare signal.alarm() di chiamare il process.terminate() dopo timeout specificato invece di lettura in un altro thread. Anche se potrebbe non interagiscono molto bene con il modulo subprocess. Sulla base di @alex Martelli risposta :

import collections
import signal
import subprocess

class Alarm(Exception):
    pass

def alarm_handler(signum, frame):
    raise Alarm

def main():
    # start process, redirect stdout
    process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)

    # set signal handler
    signal.signal(signal.SIGALRM, alarm_handler)
    signal.alarm(2) # produce SIGALRM in 2 seconds

    try:
        # save last `number_of_lines` lines of the process output
        number_of_lines = 200
        q = collections.deque(maxlen=number_of_lines)
        for line in iter(process.stdout.readline, ""):
            q.append(line)
        signal.alarm(0) # cancel alarm
    except Alarm:
        process.terminate()
    finally:
        # print saved lines
        print ''.join(q)

if __name__=="__main__":
    main()

Questo approccio funziona solo su sistemi * nix. Si potrebbe bloccare se process.stdout.readline() non restituisce.

threading.Timer soluzione

import collections
import subprocess
import threading

def main():
    # start process, redirect stdout
    process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)

    # terminate process in timeout seconds
    timeout = 2 # seconds
    timer = threading.Timer(timeout, process.terminate)
    timer.start()

    # save last `number_of_lines` lines of the process output
    number_of_lines = 200
    q = collections.deque(process.stdout, maxlen=number_of_lines)
    timer.cancel()

    # print saved lines
    print ''.join(q),

if __name__=="__main__":
    main()

Questo approccio dovrebbe funzionare anche su Windows. Qui ho process.stdout usato come un iterabile; si potrebbe introdurre un output buffering aggiuntivo, è possibile passare al metodo iter(process.stdout.readline, "") se non è desiderabile. Se il processo non termina sulla process.terminate() poi gli script si blocca.

Non ci sono discussioni, soluzione nessun segnale

import collections
import subprocess
import sys
import time

def main():
    args = sys.argv[1:]
    if not args:
        args = ['top']

    # start process, redirect stdout
    process = subprocess.Popen(args, stdout=subprocess.PIPE, close_fds=True)

    # save last `number_of_lines` lines of the process output
    number_of_lines = 200
    q = collections.deque(maxlen=number_of_lines)

    timeout = 2 # seconds
    now = start = time.time()    
    while (now - start) < timeout:
        line = process.stdout.readline()
        if not line:
            break
        q.append(line)
        now = time.time()
    else: # on timeout
        process.terminate()

    # print saved lines
    print ''.join(q),

if __name__=="__main__":
    main()

Questo uso variante né fili, nessun segnale ma produce incomprensibili uscita nel terminale. Si bloccherà se i blocchi process.stdout.readline().

Altri suggerimenti

Invece di usare "top" Io suggerisco di usare "ps", che vi darà le stesse informazioni, ma solo una volta, invece di una volta al secondo per tutta l'eternità.

Si avrà bisogno di utilizzare anche alcune bandiere con ps, tendo a usare "ps aux"

Quello che vorrei fare, piuttosto che questo approccio, è quello di esaminare il programma che si sta tentando di ottenere le informazioni da e determinare l'ultima fonte di tali informazioni. Essa può essere una chiamata API o nodo del dispositivo. Poi, scrivere qualche pitone che ottiene dalla stessa fonte. Che elimina i problemi e le spese generali di "raschiare" "cucinati" i dati.

(J.F. Sebastian i codici di grande lavoro, penso che sia meglio che la mia soluzione =))

Ho risolto utilizzando un altro modo.

Invece di fare l'output direttamente sul terminale lo faccio in un file "tmp_file":

top >> tmp_file

poi utilizzato il "taglio" strumento per rendere la sua uscita "che è uscita superiore", come valore di processo

cat tmp_file

e lo ha fatto quello che io voglio fare .Questo è il codice finale:

import os
import subprocess
import time

subprocess.Popen("top >> tmp_file",shell = True)

time.sleep(1)

os.popen("killall top")

process = os.popen("cat tmp_file").read()

os.popen("rm tmp_file")

print process

# Thing better than nothing =)

Grazie mille ragazzi aiuto

In fatti, se si riempie il buffer di uscita, vi ritroverete con una certa risposta. Così una soluzione è quella di riempire il buffer con una grande uscita di immondizia (~ 6000 personaggio con bufsize = 1).

esempio di Let, invece di top, si ha uno script python che di scrittura sul sys.stdout:

GARBAGE='.\n'
sys.stdout.write(valuable_output)
sys.stdout.write(GARBAGE*3000)

Sul lato lanciatore, invece di semplici process.readline ():

GARBAGE='.\n'
line=process.readline()
while line==GARBAGE:
   line=process.readline()

abbastanza sicuro che è un po 'sporca nel 2000 dipende sull'attuazione sottoprocesso, ma funziona bene ed è molto semplice. impostazione tutt'altro che bufsize = 1 peggiorare le cose.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top