Reading stdin with Emacs Client
Posted by Michał ‘mina86’ Nazarewicz on 21st of February 2021 | (cite)
One feature Emacs doesn’t have out of the box is reading data from standard input. Trying to open -
(e.g. echo stdin | emacs -
) results in Emacs complaining about unknown option (if it ends up starting in graphical mode) or that ‘standard input is not a tty’ (when starting in terminal).
With sufficiently advanced shell one potential solution is the --insert
flag paired with command substitution: echo stdin | emacs --insert <(cat)
. Sadly, it’s not a panacea. It messes up initial buffer (and thus may break setups with custom initial-buffer-choice
) and doesn’t address the issue of standard input not being a tty when running Emacs in terminal.
For me the biggest problem though is that it isn’t available when using emacsclient. Fortunately, as previously mentioned the Emacs Server protocol allows for far more than just instructions to open a file. Indeed, my solution to the problem revolves around the use of --eval
option:
#!/usr/bin/perl use strict; use warnings; my @args = @ARGV; if (!@args) { my $data; $data = join '', <STDIN>; $data =~ s/\\/\\\\/g; $data =~ s/"/\\"/g; $data = <<ELISP; (let ((buf (generate-new-buffer "*stdin*"))) (switch-to-buffer buf) (insert "$data") (goto-char (point-min)) (x-focus-frame nil) (buffer-name buf)) ELISP @args = ('-e', $data); } exec 'emacsclient', @args; die "emacsclient: $!\n";
People allergic to Perl may find this Python version more palatable: