Typical Technological Trickery

Reading from stdin to an emacs buffer

22 Nov 2014

Sometimes the way emacs utterly ignores standard unix conventions can be pretty annoying. In particular the fact that, unlike almost every other standard unix tool, you can’t give it - instead of a filename and have it read from stdin has always annoyed me (yes, I know emacs came from lisp machines not unix, but it’s been used on unix machines since before I was born). So today I’ve final sat down and figured out how to hack around this limitation.

First of all I should note that there is an existing package called e-sink to read from stdin. However the code seems unnecessarily complex (probably doesn’t help that I don’t know perl).

So, here’s my solution:

# The emacs or emacsclient to use
function _emacsfun
{
    # Replace with `emacs` to not run as server/client
    emacsclient -c -n $@
}


# An emacs 'alias' with the ability to read from stdin
function e
{
    # If the argument is - then write stdin to a tempfile and open the
    # tempfile.
    if [[ $1 == - ]]; then
        tempfile=$(mktemp emacs-stdin-$USER.XXXXXXX --tmpdir)
        cat - > $tempfile
        _emacsfun -e "(progn (find-file \"$tempfile\")
                             (set-visited-file-name nil)
                             (rename-buffer \"*stdin*\" t))
                 " 2>&1 > /dev/null
    else
        _emacsfun "$@"
    fi
}

If you prefer to use a standalone emacs just replace emacsclient -c -n in _emacsfun with emacs.

The function is called as

echo "hello world" | e -

or

e hello_world.txt

One more note: each time you read from stdin a temporary file in /tmp is created, these are typically cleared on reboot which is good enough for me. If you need them to be gone immediately you could add rm $tempfile inside the if statement.

As always the code is on github.