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.