Self-compiling Markdown files by misusing shebangs

🔗Has this every happened to you?

You use pandoc or some other markdown -> pdf or other format a lot. Your command invocation is long since you add a lot of configuration flags. You make it into a shell script to avoid typing the same command everytime, but for it to be reusable you have to give the .md filename as an argument.

You, like me, might not be able to withstand all these previous seconds you feel you are waisting.


You probably know that files that begin with #! ... in their first line are executed with the interpreter defined after the shebang (#!). The kernel, when called to execute something, looks for a shebang header or an INTERP field in the ELF binary headers (unrelevant to his post). If the shebang exists, it passes the control to that interpeter.

A familiar usage is starting python scripts with #!/usr/bin/env python3 or similar.

So, we can use this to make the interpreter be the markdown compiling command:

On a markdown file, say document.md:

#!/usr/bin/env -S bash -c 'pandoc --from markdown -V links-as-notes -V boxlinks -V pagestyle:empty --pdf-engine xelatex -V mainfont:'Inter-Medium' -V geometry:a6paper -t pdf -o "$(basename ${0} md)pdf" <(tail -n +2 "${0}")'

Dear reader,

This is a letter addressed to you, written in Markdown.

Author Name

Executing document.md runs the command right away. If your file is not executable, make it so with chmod u+x document.md.

Some minor explanations of the shell command:


PS: At first I was confused on why this worked; the kernel has a usually 127 or 255 byte length limit for the shebang interpreter. But it does something smart: if the first argument of the shebang is complete, it doesn’t have to bother with the bytes after the limit, since only the interpreter binary needs to know about the arguments. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/binfmt_script.c

return to index