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 inbatch
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-inserver
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 aprogn
, but this felt cleaner.-
mapc FUNCTION SEQUENCE
ApplyFUNCTION
to every object in the listSEQUENCE
.princ
Outputs the printed form of an object tostandard-out
. It's used here because it doesn't surround the string in quotes likeprint
does.-
read STREAM
ReadSTREAM
, in this case a string, and turn it into a lisp object-
server-eval-at \"server\" FORM
EvaluatesFORM
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 ofOBJECT
. I use this instead ofprinc
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 tostderr
, 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
.