#+TITLE: How to get all Emacs daemon buffers from a shell script #+DATE: 2021-05-01T22:38:32-04:00 #+DRAFT: true #+DESCRIPTION: A small script that will print all Emacs daemon buffers to stdout #+TAGS[]: emacs #+KEYWORDS[]: emacs #+SLUG: #+SUMMARY: #+ATTR_HTML: :title Emacs daemon buffers #+ATTR_HTML: :alt Emacs darmon buffers [[file:cover.png]] A while back I posted a response to someone's question on [[https://www.reddit.com/r/emacs/comments/ljtify/is_it_there_a_way_to_export_the_list_of_opened/gnhatdu/?context=3][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. #+begin_src 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' #+end_src I've simplified the lisp slightly since I answered that question. Here's the updated version. #+begin_src 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 #+end_src Here it is written in a way that's easier to read. #+begin_src 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 #+end_src Let's break it down. - =emacs= Emacs itself! - =--batch= Runs Emacs in [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Batch-Mode.html][=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=.