While there are many ways to pipe to emacs, they all involve either shuttling text by repeatedly calling emacsclient or writing to a temporary file. However, neither are necessary.

Basically, while emacs can't (yet) read from a named pipe (FIFO), it can read standard output from a process so, one gratuitous use of cat later...

(defun pager-read-pipe (fname)
  (let ((buf (generate-new-buffer "*pager*"))
        (pname (concat "pager-" fname)))
    (with-current-buffer buf (read-only-mode))
    (switch-to-buffer buf)

    (let ((proc (start-process pname buf "/usr/bin/cat" fname)))
      (set-process-sentinel proc (lambda (proc e) ()))
      (set-process-filter proc (lambda (proc string)
                                 (when (buffer-live-p (process-buffer proc))
                                   (with-current-buffer (process-buffer proc)
                                       ;; Insert the text, advancing the process marker.
                                       (let ((inhibit-read-only t))
                                         (goto-char (process-mark proc))
                                         (insert string)
                                         (set-marker (process-mark proc) (point))))))))

...and you can read a from named pipe. As an added bonus, this function will try to autodetect the correct mode.

To actually use this, I recommend the following shell script:

set -e

cleanup() {
    trap - TERM INT EXIT
    if [[ -O "$FIFO" ]]; then
        rm -f "$FIFO" || :
    if [[ -O "$DIR" ]]; then
        rmdir "$DIR" || :
trap "cleanup" TERM INT EXIT


# Create a named pipe in /dev/shm
DIR=$(mktemp -d "/dev/shm/epipe-$$.XXXXXXXXXX")
mkfifo -m 0600 "$DIR/fifo"

# Ask emacs to read from the names socket.
emacsclient -s "$SOCKET" -n --eval "(pager-read-pipe \"$FIFO\")" >/dev/null <&-

exec 1>"$FIFO"
cleanup # Cleanup early. Nobody needs the paths now...

You will probably need to set the SOCKET variable to your emacs socket filename.


$ dmesg --follow | epipe