Multiline shebang with zsh and running pyenv under cron
3 minutes read | 500 words by Ruben BerenguelThese probably qualify as the most one weird trick I have figured out this year.
Multiline shebang
Basically this is an answer to how can I configure configure the Python environment in the shebang? Like, say, to start a virtual environment. You can find many examples with bash here. But, how do you use it with zsh? And what it is?

Photo by Jan Baborák on Unsplash
It is text after a shebang expression in a script that is run by zsh, while eventually running the rest of the code. It feels a bit like a quine.
I faced this when writing my own provider script for Tip (a very recommended small app for Mac). Although it may not be required, but was fun as a problem to crack. The issue was twofold: I needed to run it under zsh
and I wanted to run my script under a virtual environment.
#!/usr/local/bin/zsh
"""true"
source /Users/ruben/.pyenvzshrc
export PYENV_VIRTUALENV_DISABLE_PROMPT=1
pyenv activate tip-provider
exec python "$0" "$@"
exit 127
"""
__doc__ = "Script for https://github.com/tanin47/tip"
[…python code in here…]
What is this? First, this is going to be executed as a zsh
script. So, we have
ZSH sees
- an empty string,
- a string containing true, which evaluates via expansion to
true
, inside quotes, so, another empty string. - Now some normal shell commands, load some scripts to prepare an environment. This
.pyenvzshrc
is a reduced.zsh
without any configuration and just there sopyenv
works as expected. - Disable the painful notification from
pyenv
- Runs python (the python from the correct environment), on this script itself with the same arguments
- Exit! This is important! This way nothing else is seen by
zsh
. It has to exit in error to prevent the shell seeing the rest.
Python sees
- A commented line (shebang)
- A triple-quoted string, which is then automatically added as the module docstring
- Modification of the docstring for consistency
- The rest
Neat, isn’t it? (not)
Running pyenv
in cron
This is a repeated issue I have faced: running things under cron fails for… shell reasons. I wanted to run bear-note-graph regularly, to always have my note graph fresh on iCloud. The goal is similar to the previous: running Python in a specific virtual environment.
Luckily, this is easier (although a bit slower):
#!/usr/local/bin/zsh
source /Users/ruben/.zshrc
pyenv activate bear-note-graph || true >/tmp/bear_graph_tmp_stdout.log 2>/tmp/bear_graph_tmp_stderr.log
bear-note-graph >>/tmp/bear_graph_tmp_stdout.log 2>>/tmp/bear_graph_tmp_stderr.log
mv /tmp/bear_graph* /Users/ruben/Library/Mobile\ Documents/com\~apple\~CloudDocs/
- Screw it and just evaluate the
.zshrc
file! (this could be changed with the modified one in the previous script) - Activate the virtual environment, and redirect any errors to create output files
- Run
bear-note-graph
with default settings (I wrote this, so the defaults are the setup I like) - Copy the results from
/tmp/
to iCloud’s root
Conclusion
Well, not much. These are interesting tricks that I want to remember, hence why I wrote this post.
Note that the first one is specific for zsh
, other shells behave slightly differently. For the second, likewise, the main issue is how to start pyenv
in a way that works.