Skip to content

Instantly share code, notes, and snippets.

@cfstras
Created April 14, 2025 15:34
Show Gist options
  • Save cfstras/5c94e39b057d383f61c73779f3e7e9e2 to your computer and use it in GitHub Desktop.
Save cfstras/5c94e39b057d383f61c73779f3e7e9e2 to your computer and use it in GitHub Desktop.
A special shebang header for python scripts that want to use uv with a pyproject.toml, but be called from any directory.
#!/usr/bin/env sh
# Special shebang: almost the same as just `uv run`, but always use the script directory to search for pyproject.toml.
# The following lines are ignored by python, and executed by bash
# Use `set -x` if you want to see what's happening
""":"
set -eu
exec uv run --project=$(dirname "$0") "$0" "$@"
"""
###
if __name__ == "__main__":
print("Hello, world!")

Universal Python UV Shebang

You've probably seen the #!/usr/bin/env -S uv run pattern popularized by Simon Willison.

One issue I've had with it: When "upgrading" scripts to get their own pyproject.toml, I can't run them from a different directory anymore!

E.g. this works:

./my_script.py

This doesn't:

some_dir/my_script.sh

This special, but longer, shebang header allows us to do that.

How?

It works like this:

  1. The first line is a shebang executing the file as a regular old POSIX script with /bin/sh.
  2. A comment follows - this is ignored by sh (and also python)
  3. Here comes the magic: We start a python block comment.
    • in Bash land, we just gave an empty string (""), followed by the start of a string (").
    • to make bash happy, we finish off with :"
    • turning that "start of a string" into "please execute :"
    • which is an alias for "true"`, or a no-op command returning 0
  4. Now, we just tell bash to run uv, but with --project $(dirname $0), so that UV knows where to search for a pyproject file.
  5. We use exec to replace the running sh, so that signals and return codes are followed
  6. We use set -eu to error out if any errors occur before uv takes over
  • unset variables
  • uv not being installed, etc.

Limitations

Tested on

  • macOS
  • Debian (Bookworm)

Probably doesn't work on Windows, unless you're using WSL or Git-Bash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment