4

I'm using emacs version 25.1.1.

I would like to run a process synchronously and have its stdout and stderr end up in two different buffers. I know I can use make-process to separate stdout and stderr in this way, but make-process runs the process asynchronously.

For synchronous process invocation, I know I could use call-process with DESTINATION being set to (list stdout-buffer stderr-file), but then I would have to manage a temporary file to catch the stderr output, and that is inefficient.

Is there any function in emacs 25.x which will allow me to run a process synchronously with its stdout and stderr ending up in different buffers?

I also see this question being raised within a comment that was posted at the end of Capturing stderr of subprocesses more than 2 years after the original query, but it isn't answered there. Perhaps that short comment was overlooked, and that's why I'm posting this as a full-fledged question here.

Thank you in advance.

2 Answers 2

3

The c-function call-process is the basis for creating synchronous processes in Emacs. So you don't get more with any other functions.

The info page (elisp) Synchronous Processes contains the following section:

You can’t directly specify a buffer to put the error output in; that is too difficult to implement. But you can achieve this result by sending the error output to a temporary file and then inserting the file into a buffer when the subprocess finishes.

So the answer to your question

Is there any function in emacs 25.x which will allow me to run a process synchronously with its stdout and stderr ending up in different buffers?

is no if you do not allow temporary files.

2
  • Yes, I know that's what the documentation states, but make-process was introduced, and it has no problems writing stderr to a buffer. Therefore, it couldn't possibly that difficult to implement that functionality. And looking at process.c within the emacs-25.1 code base, it indeed shows that this functionality is actually quite simple to code. But emacs is what it is, and since no one has implemented a synchronous way to capture stderr in a buffer, I can see that I have to live with this reality.
    – HippoMan
    Jun 4, 2018 at 23:10
  • ... however, maybe in my spare time I'll write a patch to the C code that implements call-process
    – HippoMan
    Jun 4, 2018 at 23:12
1

Another way I could do this without rewriting the C code for call-process would be to use make-process and go into a busy-wait loop that is similar to the following:

(defvar my-process-finished nil
  "*set when my process is finished")
(setq my-process-finished nil)
(defun my-sentinel (process event)
  (when (eq 'exit (process-status process))
    (setq my-process-finished t))
(make-process
   :name ...
   :command ...
   :buffer ...
   :stderr ...
   :sentinel 'my-sentinel)
(while (not my-process-finished)
  (sleep-for 0.25))
;;; continue from here

... or maybe even this:

(setq proc (make-process ... etc. ...))
(while (not (eq 'exit (process-status proc)))
  (sleep-for 0.25))
;;; continue from here

It's ugly, because I really should also check for 'failed, 'signal, and possibly other conditions. But I guess it can do the job.

... and here's my first cut at a function which will do this:

;; Does the same as `make-process`, but runs it                                                                                 
;; synchronously. Returns the exit code of                                                                                      
;; the process that is specified, or nil if                                                                                      
;; the process could not even be started.                                                                                       
(defun make-process-sync (&rest args)
  (let ((proc (apply 'make-process args)))
    (when proc
        (while (not (memq (process-status proc) '(exit failed signal)))
          (sleep-for 0.1))
        (process-exit-status proc))))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.