Как обрабатывать входные и выходные потоки в Steel Bank Common Lisp? - PullRequest
10 голосов
/ 01 марта 2010

Я пытаюсь выяснить, как использовать поток вывода одной программы, которую я начинаю с RUN-PROGRAM, чтобы его можно было использовать в качестве ввода другой программы, начинающейся с RUN-PROGRAM (т. Е. Моральный и, возможно, буквальный эквивалент трубопроводов). Я попытался использовать несколько комбинаций аргументов ключевых слов :INPUT, :OUTPUT и :WAIT, но ничего не выбрал до сих пор был продуктивным. Любые советы будут полезны; например, как бы я сделал что-то вроде ls | grep lisp из оболочки?

Одна из моих попыток

(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))))) 

Выполнение этого в SLIME REPL приводит к зависанию всего, пока я не сломаюсь с C-c C-c, так что это явно не то, но я не уверен, как это изменить, так что это правильно.

РЕДАКТИРОВАНИЕ: Добавление :WAIT NIL к обоим RUN-PROGRAM вызовам или только к вызову для grep не дает результата. В этом случае функция зависнет, и разрыв с C-c C-c получит трассировку стека, указывающую, что есть локальная функция (определенная с помощью FLET) с именем SB-UNIX:SELECT, которая зависла.

Ответы [ 3 ]

10 голосов
/ 02 марта 2010

Я получил рабочий ответ от Рэймонда Тоя на comp.lang.lisp . Его решение было для CMUCL, но оно работало с практически идентичной функцией RUN-PROGRAM в тесно связанном SBCL, и с небольшими изменениями оно будет работать и в CCL, потому что CCL RUN-PROGRAM в основном является клоном из CMUCL SBCL.

Секрет как бы в том, чтобы сначала настроить процесс ls, а затем предоставить его выходной поток процессу grep в качестве входных данных, например:

(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))))) 

Я также экспериментировал с опущением аргумента :WAIT NIL в вызове RUN-PROGRAM для ls, и это сработало так же хорошо.

1 голос
/ 27 июля 2012

Относительно, но, возможно, не точно на ваш вопрос, вы могли бы сделать:

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

или

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

или

(with-output-to-string (s)
      (ccl:run-program "ssh" (list "a-user@some-ip" "sh -c ls /a/directory/somewhere/on/remote/server/*.lisp | wc -l") :output s)
      s)

И, конечно же, вы можете использовать

(format nil "ls ~a" directory)

Чтобы получить ввод, вы можете сделать что-то вроде:

(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)
1 голос
/ 01 марта 2010

Попробуйте добавить :wait nil к своим аргументам в run-program. Это должно иметь как ваш grep, так и ваш ls, работающий в фоновом режиме. Таким образом, вы запускаете процесс grep, ожидаете его завершения, а затем запускаете команду ls, которую вы намереваетесь ввести в процесс grep. Увы, так как вы ждете окончания grep, вы никогда не доберетесь до этого.

...