2010-03-01 13 views
9

Estoy tratando de averiguar cómo usar la secuencia de salida de un programa. Empiezo con RUN-PROGRAM para que pueda usarse como la entrada de otro programa iniciado con RUN-PROGRAM (es decir, el equivalente moral y quizás literal de la tubería). He intentado utilizar una serie de combinaciones de los argumentos de palabras clave :INPUT, :OUTPUT y :WAIT, pero nada de lo que haya pulsado ha sido productivo hasta el momento. Cualquier consejo sería de ayuda; por ejemplo, ¿cómo haré para hacer algo como ls | grep lisp desde el caparazón?Cómo procesar flujos de entrada y salida en Steel Bank Common Lisp?

Una de mis intentos es

(defun piping-test() 
    (let ((grep-process (run-program "/usr/bin/grep" '("lisp") 
            :input :stream 
            :output :stream))) 
    (unwind-protect 
     (with-open-stream (s (process-input grep-process)) 
      (let ((ls-process (run-program "/bin/ls" '() 
             :output s))) 
      (when ls-process 
       (unwind-protect 
        (with-open-stream (o (process-output grep-process)) 
        (loop 
         :for line := (read-line o nil nil) 
         :while line 
         :collect line)) 
       (process-close ls-process))))) 
    (when grep-process (process-close grep-process))))) 

La ejecución de este en un BABA REPL hace todo lo posible para colgar hasta que rompa con C-c C-c, así que no es bastante obvio lo correcto, pero estoy no está seguro de cómo cambiarlo para que sea lo correcto.

EDIT: Adición de:WAIT NIL a ambos RUN-PROGRAM invocaciones, o solamente a la invocación de grep, no hacer el truco. En ese caso, la función se bloqueará, y romper con C-c C-c obtiene un seguimiento de la pila que indica que hay una función local (definida a través de FLET) llamada SB-UNIX:SELECT que se colgó.

Respuesta

10

Recibí una respuesta de trabajo de Raymond Toy en comp.lang.lisp. Su solución fue para CMUCL, pero funcionó con la función esencialmente idéntica RUN-PROGRAM en el SBCL estrechamente relacionado, y con cambios menores también funcionará en CCL, porque el RUN-PROGRAM de CCL es básicamente un clon del de CMUCL/SBCL.

El secreto, por así decirlo, es configurar el proceso ls primero, y luego proporcionar su flujo de salida para el proceso grep como entrada, así:

(defun piping-test2() 
    (let ((ls-process (run-program "/bin/ls" '() 
           :wait nil 
           :output :stream))) 
    (unwind-protect 
     (with-open-stream (s (process-output ls-process)) 
      (let ((grep-process (run-program "/usr/bin/grep" '("lisp") 
              :input s 
              :output :stream))) 
      (when grep-process 
       (unwind-protect 
        (with-open-stream (o (process-output grep-process)) 
        (loop 
         :for line := (read-line o nil nil) 
         :while line 
         :collect line)) 
       (process-close grep-process))))) 
     (when ls-process (process-close ls-process))))) 

también he experimentado con la omisión de la :WAIT NIL argumento de la llamada RUN-PROGRAM para ls, y funcionó igual de bien.

1

Intente agregar :wait nil a sus argumentos al run-program. Eso debería tener tanto tu grep como tu l ejecutándose en segundo plano. Como está, estás iniciando el proceso grep, esperando que termine, y luego comienzas el ls que piensas alimentar en el proceso grep. Por desgracia, ya que estás esperando que termine el grep, nunca llegas tan lejos.

1

En relación con esto, pero tal vez no en el clavo a su pregunta, usted podría hacer:

(with-output-to-string (s) 
     (ccl:run-program "sh" (list "-c" "ls a/directory/somewhere/*.lisp") :output s) 
     s) 

o

(with-output-to-string (s) 
     (ccl:run-program "sh" (list "-c" "ls /a/directory/somewhere/*.lisp | wc -l") :output s) 
     s) 

o

(with-output-to-string (s) 
     (ccl:run-program "ssh" (list "[email protected]" "sh -c ls /a/directory/somewhere/on/remote/server/*.lisp | wc -l") :output s) 
     s) 

Y, por supuesto, puede utilizar

(format nil "ls ~a" directory) 

Para obtener la entrada, se puede hacer algo como:

(with-output-to-string (out) 
     (format t "~%Enter your sudo password:~%") 
     (with-input-from-string (s (read)) 
     (ccl:run-program "ssh" (list *remote* "sudo cat /etc/init.d/nginx") :input s :output out)) 
     out)