Introduction

An #emacs IRC user wants to pipe from a program into an Emacs buffer. emacsclient doesn’t read standard input1. So, is there a way to do this with emacsclient and not writing a new server program? I think so.

We’ll use a shell script called “pipe-to-emacs-buffer.sh”. It will take a single argument, the name of a buffer to receive the data. The Emacs Lisp code will create this buffer and set it as the current buffer.

Shell script

Start

# pipe-to-emacs-buffer.sh buffer-name

if [ $# -lt 1 ]
then
    echo usage: pipe-to-emacs-buffer.sh buffer-name
    exit 1
fi

buffername="$1"

Base64 encode standard input

So why base64 encoding? If standard input has non-text characters, e.g. a NUL, the string gets mangled. Encoding ensures the data is preserved.

input=$(base64)

This assumes that the program feeding the pipe is not a long-running program that never quits. In the case of a long running program, this code could be extended to use a loop of the shell’s read builtin and encoding to get all of the data over time, or make some decision not to get all the data.

Run emacsclient

emacsclient --eval "(set-buffer (get-buffer-create \"${buffername}\"))" --eval "(insert (base64-decode-string \"${input}\"))"

get-buffer-create will either use an existing buffer or create one.

insert will insert the text before point.

Let’s test it!

Here’s the output of who on my laptop:

davemarq seat0        2025-11-11 09:44
davemarq tty2         2025-11-11 09:44

So piping who into our program, along with the buffer name who.txt, should result in a buffer named who.txt in our running Emacs.

davemarq:~$ who | ./pipe-to-emacs-buffer.sh who.txt
#<buffer who.txt>
nil

Looking at our buffer list, I see who.txt:

* who.txt                                78 Fundamental      

Going to the who.txt buffer, I see

davemarq seat0        2025-11-11 09:44
davemarq tty2         2025-11-11 09:44

Running our pipeline a second time gives me a who.txt buffer that looks like this:

davemarq seat0        2025-11-11 09:44
davemarq tty2         2025-11-11 09:44
davemarq seat0        2025-11-11 09:44
davemarq tty2         2025-11-11 09:44

Footnotes

1 In reading emacsclient.c, it does read standard input, but prepends “-eval “ to every line before sending to Emacs. But this is not documented and didn’t work as I expected when I tried it.