Emacs can invoke processes either synchronously or asynchronously. In the former case, the calling program has to wait for the process to terminate before processing the entire output in one go (whether character-wise, line-wise, or other-wise is up to the program). In the latter case, the program can still wait for the process to terminate before processing its output, but the program additionally has the ability to process intermediate output in chunks of any size it likes.
Here's an example of processing entire synchronous output in line-wise fashion:
(require 'cl-lib) ; For `cl-oddp'
(defun my-process-line (line)
"Print LINE if it comprises an odd number."
(when (ignore-errors (cl-oddp (string-to-number line)))
(message ">>> %s" line)))
(mapc #'my-process-line (process-lines "seq" "10"))
This generates the following output:
>>> 1
>>> 3
>>> 5
>>> 7
>>> 9
If process-lines
is too slow (less likely) or inflexible (more likely), you can achieve the same effect with call-process
:
(mapc #'my-process-line
(split-string (with-output-to-string
(call-process "seq" nil standard-output nil "10"))
"\n" t))
Equivalently, with slightly better performance due to less GC:
(with-temp-buffer
(call-process "seq" nil t nil "10")
(goto-char (point-min))
(while (not (eobp))
(my-process-line
(buffer-substring-no-properties (point) (line-end-position)))
(forward-line)))
Here's the same example, but invoked asynchronously:
(defun my-sentinel (proc _msg)
"Process entire output of PROC line-wise."
(when (and (eq (process-status proc) 'exit)
(zerop (process-exit-status proc))
(buffer-live-p (process-buffer proc)))
(with-current-buffer (process-buffer proc)
(mapc #'my-process-line (split-string (buffer-string) "\n" t))
(kill-buffer))))
(let ((process-connection-type nil))
(set-process-sentinel (start-process "my-proc" " *my-proc*" "seq" "10")
#'my-sentinel))
Equivalently, using the Emacs 25 function make-process
:
(make-process :name "my-proc"
:buffer " *my-proc*"
:command '("seq" "10")
:connection-type 'pipe
:sentinel #'my-sentinel)
Here's the same example, but with the output processed in chunks as it comes in, rather than after it's complete:
(defun my-filter (proc str)
"Process each line produced by PROC in STR."
(when (buffer-live-p (process-buffer proc))
(with-current-buffer (process-buffer proc)
(insert str)
(goto-char (point-min))
(while (progn (skip-chars-forward "^\n")
(not (eobp)))
(my-process-line (delete-and-extract-region (point-min) (point)))
(delete-char 1)))))
(let* ((process-connection-type nil)
(proc (start-process "my-proc" " *my-proc*" "seq" "10")))
(set-process-filter proc #'my-filter)
(set-process-sentinel proc #'my-sentinel))
Equivalently, using make-process
:
(make-process :name "my-proc"
:buffer " *my-proc*"
:command '("seq" "10")
:connection-type 'pipe
:filter #'my-filter
:sentinel #'my-sentinel)
As lunaryorn mentioned in a comment, the reason your sample asynchronous script fails to print anything is because it exits before being given the chance to accept output from its subprocess; you need to block somehow until the process has terminated. One way to do this is to use call-process
et al. synchronously, but then you forgo the ability to process output lines as they come in. Another way is to block until the asynchronous subprocess is done:
(let* ((process-connection-type nil)
(proc (start-process "my-proc" " *my-proc*" "seq" "10")))
(set-process-filter proc #'my-filter)
(set-process-sentinel proc #'my-sentinel)
(while (accept-process-output proc)))
Equivalently, using make-process
:
(let ((proc (make-process :name "my-proc"
:buffer " *my-proc*"
:command '("seq" "10")
:connection-type 'pipe
:filter #'my-filter
:sentinel #'my-sentinel)))
(while (accept-process-output proc)))
The gory details for all of this and more are documented under (elisp) Processes
.