如何在emacs lisp中等待/捕获aysnchronous shell命令输出?

时间:2010-08-26 06:28:31

标签: elisp

如果我在emacs lisp中异步执行shell命令,如下所示:

(shell-command“mycommand&”)

有没有办法在继续之前等待命令生成输出?对于我当前的应用程序,可能需要等到命令生成任何输出,但理想情况下我想捕获输出以进行其他处理。这可能吗?

2 个答案:

答案 0 :(得分:4)

也许您需要注册一个进程过滤器来为您提供所需的回调时间?请参阅37.9 Receiving Output from Processes in the Elisp manual(我在Emacs 22.3的副本中看到了这一点。)

以下是获取第一个进程输出并将其存储到“关联缓冲区”时运行回调的示例。将其复制到*scratch*缓冲区并eval-region,但请确保拆分窗口并显示*Messages*缓冲区,以便您可以看到正在发生的事情。

;; this is emacs lisp (and a comment line)
(defvar my-callback-got-some-already nil)

(defun my-callback ()
  (message "callback ran at   %s" (current-time-string)))

(defun my-filter-waits-for-first-time-input (proc string)
  (unless my-callback-got-some-already
    (setq my-callback-got-some-already t)
    ;; do your one-time thing
    (my-callback))
  ;; insert into the associated buffer as if no process filter was
  ;; registered
  (with-current-buffer (process-buffer proc)
    (let ((moving (= (point) (process-mark proc))))
      (save-excursion
        ;; Insert the text, advancing the process marker.
        (goto-char (process-mark proc))
        (insert string)
        (set-marker (process-mark proc) (point)))
      (if moving (goto-char (process-mark proc))))))

(defun async-callback-test-harness ()
  (interactive)
  (let ((process-handle "async-callback-test")
        (associated-process-buffer "*async-callback-test*")
        (command "ls")
        (busy-loop-var ""))
  (setq my-callback-got-some-already nil)
  (message "start test        %s" (current-time-string))
  (start-process process-handle associated-process-buffer command)
  ;; Supposedly async but Emacs doesn't get the input until
  ;; "Emacs is waiting" so the following set-process-filter
  ;; can be registered in time.
  ;; To prove the point, make emacs busy loop to show that the
  ;; emacs doesn't drop its input and 
  ;; the callback will get the unskipped input.
  (switch-to-buffer associated-process-buffer)
  (dotimes (k 2000) ; about two seconds on my machine
    (setq busy-loop-var (concat busy-loop-var "busy looping...")))
  (message "done busy waiting %s" (current-time-string))
  (set-process-filter (get-process process-handle)
                      'my-filter-waits-for-first-time-input)
  nil))

;; run it!
(async-callback-test-harness)

答案 1 :(得分:3)

在输出插入缓冲区后,您应该使用包含函数的comint-output-filter-functions变量。

例如,你可以这样做:

(add-hook 'comint-output-filter-functions '(lambda (txt) (message "hello")))

N.B。 :从Emacs 23.2开始,你有了新命令async-shell-command,全局绑定到 M-& 。 这将异步执行您的命令,而不需要&符号。命令的输出发送到缓冲区 *Async Shell Command*