2013-05-29 90 views
4

我有一個效用函數:運行命令異步,但顯示輸出逐步

(defun execute-in-buffer (command-with-args buffer) 
    "Execute a string COMMAND-WITH-ARGS representing a shell command with arguments, 
inserting the results in BUFFER." 
    (switch-to-buffer buffer) 
    (insert (format ">>> %s\n" command-with-args)) 
    (let* ((command-args-list (s-split " " command-with-args)) 
     (command (car command-args-list)) 
     (args (cdr command-args-list))) 
    (apply 'call-process command nil buffer t args))) 

這讓我做的事情一樣(execute-in-buffer "ls /" (get-buffer-create "*my-output*")。但是,它不適合慢速命令。如果我叫了一系列緩慢的命令,我沒有得到任何輸出,直到最後一刻:

(let ((buf (get-buffer-create "*my-output"))) 
    (execute-in-buffer "sleep 10" buf) 
    (execute-in-buffer "ls /" buf)) 

我希望能夠同步調用,所以前一結束之後的下一個命令只運行。但是,我想在運行命令時看到命令的輸出。我將如何做到這一點?

(示例代碼是作秀,我很高興地放棄它贊成別的東西。)

+1

你不應該用'with-current-buffer'或者'set-buffer'而不是'switch-to-buffer'? – sds

+0

這是設計 - 我想讓我的輸出緩衝區可見。在其他情況下,我肯定會使用'with-current-buffer'或'set-buffer'。 –

+1

在這種情況下,你需要使用'set-buffer'和display-buffer'。 – sds

回答

7

使用同步過程

如果你想堅持的同步過程(例如使用call-process),您需要在每次致電execute-in-buffer後致電(redisplay),以便更新顯示並使輸出可見(另請參閱this question瞭解更多詳情)。但是,每個命令的輸出在進程終止之前都不可見,並且在外部進程運行時emacs將掛起。

使用異步處理

使用異步過程是一個比較複雜一點,但避免了掛Emacs的,而命令正在運行,這也解決了重新顯示的問題。這裏棘手的部分是順序鏈接所有命令。這是一個有點elisp的的應該做的伎倆:

(defun execute-commands (buffer &rest commands) 
    "Execute a list of shell commands sequentially" 
    (with-current-buffer buffer 
    (set (make-local-variable 'commands-list) commands) 
    (start-next-command))) 

(defun start-next-command() 
    "Run the first command in the list" 
    (if (null commands-list) 
     (insert "\nDone.") 
    (let ((command (car commands-list))) 
     (setq commands-list (cdr commands-list)) 
     (insert (format ">>> %s\n" command)) 
     (let ((process (start-process-shell-command command (current-buffer) command))) 
     (set-process-sentinel process 'sentinel))))) 

(defun sentinel (p e) 
    "After a process exited, call `start-next-command' again" 
    (let ((buffer (process-buffer p))) 
    (when (not (null buffer)) 
     (with-current-buffer buffer 
     ;(insert (format "Command `%s' %s" p e)) 
     (start-next-command))))) 

;; Example use 
(with-current-buffer (get-buffer-create "*output*") (erase-buffer)) 
(execute-commands "*output*" 
        "echo 1" 
        "sleep 1" 
        "echo 2; sleep 1; echo 3" 
        "ls /") 
+0

謝謝,這大大改善了事情。但是,理想情況下,我希望看到命令的輸出存在,​​而不是等待命令終止。 –

+0

我添加了一個基於異步進程的解決方案,它應該可以解決這個問題。請看我編輯的答案 – Francesco

+0

精美的作品,謝謝! :) –

5

這個工作對我來說:

(async-shell-command "echo 1; sleep 10; echo 2; sleep 10; ls /" "*abcd*") 

這可以適應你需要什麼?

+0

哦,這非常接近。在我原來的'execute-in-buffer'中,我還顯示了我運行之前運行的命令。我看不到任何干淨利落的做法(async-shell-command「echo \」echo 1 \「; echo 1;」)「等等。 –

+1

如果這是個人使用 - 與產品化功能 - '(async-shell-command「set -xv; echo 1; sleep 10; echo 2; sleep 10; ls /」「* abcd *」)'可能適合你 –