Emacs darmon buffers

A while back I posted a response to someone's question on reddit about how to get a list of all Emacs daemon buffers from a shell script. It was a pretty interesting problem so I thought I'd explain my answer here.

The question was "Is it there a way to export the list of opened buffers to STDOUT?".

In the comments I left a rather byzantine looking snippet of code that I'd managed to produce.

emacs --batch --eval "(require 'server)" --eval "(mapc #'print (read (server-eval-at \"server\" '(format \"%s\" (mapcar (lambda (buffer) (format \"\\\"%s\\\"\n\" buffer)) (buffer-list))))))" | sed '/^$/d; s/^"//g; s/"$//g'

I've simplified the lisp slightly since I answered that question. Here's the updated version.

emacs --batch --eval "(require 'server)" --eval "(mapc #'princ (read (server-eval-at \"server\" '(prin1-to-string (mapcar (lambda (buffer) (format \"%s\\n\" buffer)) (buffer-list))))))" 2>/dev/null

Here it is written in a way that's easier to read.

emacs --batch \
      --eval "(require 'server)" \
      --eval "(mapc #'princ
                    (read (server-eval-at \"server\"
                             '(prin1-to-string (mapcar (lambda (buffer)
                                                           (format \"%s\\n\" buffer))
                                                       (buffer-list))))))" \
      2>/dev/null

Let's break it down.

  • emacs Emacs itself!

    • --batch Runs Emacs in batch mode, which executes commands non-interactively and stops it from opening a window. This is usually used for running Emacs lisp as a script.

    • --eval Evaluates the following piece of elisp in the batch Emacs

      • (require 'server) Loads the built-in server package. This is used to connect to the running Emacs daemon

    • --eval Since the previous elisp snippet was a complete s-expression I evaluate the next expression as a new argument. I could have also wrapped them both in a progn, but this felt cleaner.

      • mapc FUNCTION SEQUENCE Apply FUNCTION to every object in the list SEQUENCE.

        • princ Outputs the printed form of an object to standard-out. It's used here because it doesn't surround the string in quotes like print does.

        • read STREAM Read STREAM, in this case a string, and turn it into a lisp object

          • server-eval-at \"server\" FORM Evaluates FORM on the Emacs daemon and returns the result. The quotes are escaped because it's already inside a quote because it's a command line argument.

            • prin1-to-string OBJECT Return a string containing the printed representation of OBJECT. I use this instead of princ because that outputs the result to the minibuffer of the Emacs daemon instead of returning it.

              • mapcar FUNCTION SEQUENCE Applies FUNCTION to each element of SEQUENCE and returns a list of the result.

                • (lambda (buffer) (format \"%s\\n\" buffer) An anonymous function that takes a buffer and returns the string version of its name followed by a newline. The quotes and newline are escaped because it's already inside a quote because it's a command line argument.

                • buffer-list Returns a list of all buffers in Emacs

    • 2>/dev/null Send the Emacs startup text, which is outputted to stderr, to /dev/null. We don't want to see it.

The result is a single line command that outputs the name of every buffer in the Emacs daemon, one per line, to stdout.