Como processar fluxos de entrada e saída no Banco de aço Lisp comum?
-
23-09-2019 - |
Pergunta
Estou tentando descobrir como usar o fluxo de saída de um programa que começo RUN-PROGRAM
Portanto, pode ser usado como a entrada de outro programa começou com RUN-PROGRAM
(ou seja, o equivalente moral e talvez literal da tubulação). Eu tentei usar várias combinações do :INPUT
, :OUTPUT
e :WAIT
Argumentos de palavras -chave, mas nada que eu acabei foi produtivo até agora. Quaisquer dicas serão úteis; por exemplo, como eu iria fazer algo como ls | grep lisp
da concha?
Uma das minhas tentativas é
(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)))))
Executar isso em um lodo Repl faz com que tudo fique pendurado até eu quebrar com C-c C-c
, então, obviamente, não é a coisa certa, mas não tenho certeza de como alterá -lo, por isso é a coisa certa.
EDITAR: Adicionando :WAIT NIL
para ambos RUN-PROGRAM
invocações, ou apenas para a invocação para grep
, não faz o truque. Nesse caso, a função vai pendurar e quebrar com C-c C-c
recebe um rastreamento de pilha indicando que há uma função local (definida via FLET
) chamado SB-UNIX:SELECT
Isso pendurou.
Solução
Recebi uma resposta funcional de Raymond Toy On Comp.lang.lisp. Sua solução era para CMUCL, mas funcionou com o essencialmente idêntico RUN-PROGRAM
Função no SBCL intimamente relacionado e, com pequenas mudanças, também funcionará no CCL, porque o CCL's RUN-PROGRAM
é basicamente um clone do CMUCL/SBCL.
O segredo, por assim dizer, é configurar o ls
processar primeiro e depois fornecer seu fluxo de saída para o grep
Processar como entrada, assim:
(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)))))
Eu também experimentei omitir o :WAIT NIL
argumento do RUN-PROGRAM
chamar para ls
, e funcionou da mesma forma.
Outras dicas
Tente adicionar :wait nil
para seus argumentos para run-program
. Isso deve ter o seu grep e seu LS em segundo plano. Como está, você está iniciando o processo Grep, esperando que isso termine e, em seguida, inicia o LS que pretende alimentar no processo de Grep. Infelizmente, como você está esperando o grep terminar, você nunca chega tão longe.
De forma semelhante, mas talvez não seja a sua pergunta, você pode fazer:
(with-output-to-string (s)
(ccl:run-program "sh" (list "-c" "ls a/directory/somewhere/*.lisp") :output s)
s)
ou
(with-output-to-string (s)
(ccl:run-program "sh" (list "-c" "ls /a/directory/somewhere/*.lisp | wc -l") :output s)
s)
ou
(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)
E, claro, você pode usar
(format nil "ls ~a" directory)
Para obter informações, você pode fazer 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)