2016-01-25 43 views
6

Sto generando un processo dal programma Common Lisp (gnuplot). Sono in grado di stabilire flussi di input e output per il processo. Tuttavia, ho un problema a leggere dall'output. Il problema è che voglio provare a leggere dall'output, e se non c'è niente, beh ... non fare nulla per esempio.Come rilevare se il flusso di input è vuoto (ma non EOF)?

(problema di base: Voglio leggere il risultato del comando show term ma voglio saltare qualsiasi altra uscita che gnuplot avrebbe potuto produrre prima di inviare il comando)

Se mi basta usare (read-line gnuplot-output nil :eof) e non c'è niente in flusso di output, non indicherà :eof (poiché lo stream è ancora attivo e qualcosa potrebbe apparire lì) e bloccherà solo finché non avrà qualcosa da leggere (cioè per sempre).

C'è un modo per rilevare che non c'è niente da leggere? Almeno, in qualche modo, è possibile sospendere il tentativo di leggere (cioè non dovrebbe far scoppiare una nuova riga dal flusso una volta scaduto il time-out)?

PS. Sto usando SBCL

risposta

5

Listen dovrebbe dirti se c'è un personaggio disponibile. Penso che dovrai leggere lo stream carattere per carattere piuttosto che intere righe alla volta, a meno che tu non sia sicuro che il programma non emetta mai una riga incompleta.

Edit: Un test rapido (usando sb-ext per l'esecuzione del programma):

(defun test() 
    (do* ((program (run-program "output-test.sh" nil 
           :search t 
           :output :stream 
           :wait nil)) 
     (output-stream (process-output program))) 
     ((not (process-alive-p program))) 
    (if (listen output-stream) 
     (loop 
      for char = (read-char-no-hang output-stream nil nil) 
      while char 
      do (write-char char)) 
     (format t "No output available.~%")) 
    (sleep 1))) 

Dove output-test.sh è:

#!/bin/sh 
for item in * 
do 
    echo $item 
    sleep 3 
done 
+1

1+ Per OP: vedi anche 'read-char-no-hang' – coredump

+0

Con' read-char-no-hang', non è necessario usare 'listen'. Inoltre, il collasso delle associazioni variabili da un 'esterno' let'/let *' al 'do' /' do * 'interno, come avete fatto in una delle vostre modifiche, ostacola la leggibilità del codice e la manutenibilità, solo per salvare alcuni caratteri. Sia 'program' che' output-stream' non variano nel ciclo, quindi lasciarli in un 'let' /' let * 'lo renderebbe ovvio. – acelent

+0

@acalent Il 'listen' è per controllare se c'è qualcosa da leggere, senza leggerlo. Usare solo 'read-char-no-hang' consumerebbe il primo carattere dell'input, rendendo la logica più complicata. Per quanto riguarda il fatto di avere i collegamenti variabili in un 'let' separato, pensavo che all'inizio sarebbe stato più chiaro, ma poi ho capito che dal momento che il ciclo dovrebbe funzionare fino all'uscita dal programma, ha senso avviare il programma nei loop inizializzazione. In questo modo l'intera durata del processo figlio si trova in un unico posto. – jkiiski