[HN Gopher] Using uv as your shebang line
___________________________________________________________________
Using uv as your shebang line
Author : Einenlum
Score : 451 points
Date : 2025-01-28 17:35 UTC (1 days ago)
(HTM) web link (akrabat.com)
(TXT) w3m dump (akrabat.com)
| thecodemonkey wrote:
| What is uv?
| woodruffw wrote:
| https://github.com/astral-sh/uv
| avidiax wrote:
| Seems that it interprets a special comment block, then
| automatically creates a python venv and gathers dependencies.
| As the post[1] says, it obviates "faffing" with venv and pip to
| run a script.
|
| https://akrabat.com/defining-python-dependencies-at-the-top-...
| benreesman wrote:
| It's a package manager for Python (among other things) that is
| simultaneously correct and performant. It's getting a lot of
| attention these days.
|
| I highly recommend it over all conceivable alternatives.
| IgorPartola wrote:
| How likely is this to be another npm/yarn situation? I have
| used a number of Python tools that in the long run turned out
| to be less portable and less usable than plain Pip and
| virtualenv. I do use pyenv for a personal setup but not for
| any production use.
| d0mine wrote:
| You can use uv and get the benefits today: it combines the
| functionality from several tools (including pyenv) and the
| performance is such that it is transformative.
| baq wrote:
| as if it was so simple. don't forget about pnpm.
|
| it's the same for uv/pip/poetry except uv is so much better
| than the alternatives there isn't any contest. pip is the
| safe default (which doesn't even work out of the box on
| debian derivatives, which is half the issue) and uv is...
| just default.
| Arrowmaster wrote:
| As a Debian user that wanted to use a cli tool only
| available from npm it was horrible trying to find some
| sane instructions that didn't assume intimate knowledge
| of node package structures.
|
| I did eventually figure out I could just do `corepack
| pnpm setup` then install packages globally with pnpm.
| einpoklum wrote:
| The idea is as follows:
|
| * A recently-published PEP specificies how Python scripts can
| declare dependencies in opening comments.
|
| * uv is a Python script-runner/package manager which scans for
| those dependencies, arranges for them to be met, and runs the
| script with those dependency modules available for importing
|
| * If, in a Python script, you use the first line comment - the
| shebang line - to have the file invoked using uv rather than
| python itself, you'll get that effect automagically when
| "running" the Python script
|
| The result: Python scripts which require setup of dependencies
| will now "just run".
| bityard wrote:
| (If you have `uv` installed in your $PATH.)
|
| Also, uv will install the dependencies, but I am not clear on
| whether or not it will automatically install a Python
| interpreter for you using this method.
| kjkjadksj wrote:
| Will now "just run" after you satisfied the dependency of
| installing uv on your system and prepending these dependency
| lines to all your scripts, that is.
|
| Imo this saves you no time over just constructing and calling
| environments the old way. I'm not sure either whether uv lets
| you load the env only in an interactive session or if its just
| for script running.
| einpoklum wrote:
| I'll first day I'm not a proponent of uv, I just read the
| post and tried to clarify what it says...
|
| but I think what it saves you is the trouble of setting up a
| virtual environment the "old" way. So, it's about making
| things easier, not faster.
| fastasucan wrote:
| Ofcourse it does, after you have installed uv and prepending
| the dependencies you never have to do it again. Calling
| environments etc have to be done every time. You also have to
| keep these env around.
| vunderba wrote:
| I've been meaning to look into uv. However, since I make pretty
| heavy use of conda for my pythons scripts, I'll usually add a
| bash function that handles conda activation / code execution to
| my .zshrc file. function transcribe() { #
| get the active conda environment active_env=$(conda info
| | grep "active environment" | awk '{print $4}') if
| [[ "$active_env" != "speechrec-env" ]]; then conda
| activate speechrec-env fi python
| /users/vunderba/dev/transcriber/transcribe.py "$@" }
|
| It's handy because if it'll always point to the most current
| version of my script.
| kjkjadksj wrote:
| What seems to suck about the uvx way of doing things is that
| your script and dependencies are now in one document. It just
| seems so much more useful for so many reasons to keep these
| things discrete in my mind. Especially when we are talking
| about uvx which is something probably only a fraction of python
| devs actually use vs a built in paradigm of the language. Yes,
| conda is not built in but it might as well be with the amount
| of influence it has on python development and downstream tools
| to manage conda envs (e.g. mamba or snakemake).
| babel_ wrote:
| That's not the uvx way? Dependencies at the top of a script
| was outlined in PEP 723, which uv/uvx added support for. Not
| everything is a "project", some files are just one-and-done
| scripts which should not have to carry the burden of
| project/environment management, but absolutely should still
| be able to make use of dependencies. The "uvx way" of doing
| it just means that it doesn't have to pollute the global/user
| install, and can even be isolated into a separate instance.
|
| Besides, not everyone uses conda, and it would be quite a
| stretch to say it "might as well" be a built-in compared to,
| well, the actual built in, pip! Plus, uv works quite nicely
| as "just a pip replacement", which is how I started with it,
| so it aligns quite well to the actual built-in paradigm of
| the language.
| simonw wrote:
| That's a misundersanding of uv - the inline script
| dependencies feature is strictly optional. You're encouraged
| to use pyproject.toml as a default instead of that for most
| projects. https://docs.astral.sh/uv/guides/projects/
| krick wrote:
| Wow, this is super obvious (so obvious that it wouldn't occur to
| me to write a post to brag about it), yet it somehow didn't occur
| to me. Very cool.
|
| Not so long ago I started pip-installing my scripts to keep
| things tidy. It seems now I can regress back to chaos again...
| nomel wrote:
| My favorite way to pass small scripts to non software
| colleagues: try: import package
| except ImportError: import pip
| print("Installing package...") pip.main(['install',
| 'package'] import package
|
| :D
| hv42 wrote:
| You can use this trick with mise (mise-en-place) for small tasks:
| https://mise.jdx.dev/tasks/toml-tasks.html#shell-shebang
| [tools] uv = 'latest' [tasks.python_uv_task]
| run = """ #!/usr/bin/env -S uv run --script # ///
| script # dependencies = ["requests<3", "rich"] # ///
| import requests # your code here """
| kseistrup wrote:
| Something similar is shown for uv here:
| https://simonwillison.net/2024/Aug/21/usrbinenv-uv-run/
| threecheese wrote:
| I e experienced a few "gotchas" using uv (or uvx) as a command
| runner, but when it works (which is most of the time) it's a big
| time saver. As a Python dev and curious person my homedir is
| littered with shallow clones and one-off directories for testing
| some package or another, and not having to manage this overhead
| is really useful.
|
| OP, you have a great idea and I'm stealing it. Do you use some
| non-.py suffix, or is seeing the exec bit at on a .py file enough
| of a signal for you to know that you can just run the file as a
| script (and it won't use the system Python)?
| przemub wrote:
| From what I understand, he uses .py with exec bit and the
| shebang line as in the article.
| BiteCode_dev wrote:
| I've been collecting gotchas from using uv myself over the last
| year to assess whether to recommend it or not and I found
| surprisingly few. Not zero, but I'm looking pretty hard.
|
| Would love to hear what gotchas to find so I can add that to
| the list.
| achierius wrote:
| Is the list public? I'm trying to figure out whether it's
| worth taking the plunge.
| BiteCode_dev wrote:
| I'll write an article on bitecode.dev at the one year mark
| (about end of feb) about the various situations I tested it
| in with clients and the results.
|
| I will include a section about the things that it was not
| good for and the problems with it. Spoiler, there were not
| that many and they fixed them astonishingly well (even one
| this week!). But obviously there were some, no software is
| perfect although they worked hard to not make it too
| opinionated for the first taste.
|
| I can ping you when it comes out.
| EdwardDiego wrote:
| Really curious as to your gotchas.
|
| One thing that hit me in Pipenv, but worked well in Poetry, is
| when a given dep has different wheels for different platforms.
|
| The pipenv lock lockfile would only include the deps for the
| platform you locked it on.
|
| Poetry adds all platform variants to the lockfile.
|
| And haven't found any documentation around uv's behaviour in
| this regard.
| zahlman wrote:
| I really don't understand how it is that other people frequently
| write one-off scripts that nevertheless need to run in an
| isolated environment (as opposed to a sandbox that contains a few
| common workhorse packages like NumPy or Requests).
|
| Of course I have plenty of separate environments set up, but
| that's because I'm _developing_ things I hope to share with
| others, so I need to keep close track of their specific
| dependencies (so I can specify them in package metadata). But
| even this stuff would generally work with a wide range of
| versions for those dependencies. I 'd imagine this is equally
| true of small, one-off, personal automation scripts.
|
| But, sure, if you have this problem, that's a great way to use
| the shebang line. (You can do similarly with Pipx, and I expect
| you'll be able to with Paper as well, although I might push that
| sort of thing into an optional add-on.)
| traverseda wrote:
| It's when you need to give the script to someone else.
| imtringued wrote:
| They don't care about the isolated environment. They care about
| having the right dependencies available to the script.
|
| Competing languages like Java don't need or even have the
| concept of isolated environments. It's an illogical concept.
| You have a class path and that is about it.
| orf wrote:
| A virtual environment is just a project-specific class path,
| but for Python.
| tcptomato wrote:
| Which also installs a complete JVM in it.
| zahlman wrote:
| Not really; it can just symlink the base executable and
| make a few folders and scripts. $
| python -m venv --without-pip test-venv && du -sh test-
| venv 56K test-venv
| dragonwriter wrote:
| Conceptually, a venv has its own executable.
|
| Physically, that can just be a symlink to the system
| python (or another version that is still potentially
| shared with multiple venvs.)
| simonw wrote:
| That's one of the great things about uv: it uses clever
| symlink tricks to avoid installing copies of things, so
| it's wildly fast.
| zahlman wrote:
| >They care about having the right dependencies available to
| the script.
|
| Right; my point is that I'd expect one-off scripts like this
| to keep relying on the same few standard dependencies which
| would already have been set up in an environment somewhere.
|
| >You have a class path and that is about it.
|
| A Python venv pretty much is just a layer on top of the
| existing "class path" mechanism (sys.path) to point it at the
| right place automatically (reproducing the basic folder
| layout relative to a symlinked executable, so that sys.path
| ends up with the right paths and so that there's a dedicated
| folder for installing the dependencies). While it's ugly and
| not recommended, you can work with the PYTHONPATH environment
| variable, or even modify sys.path at runtime.
| SAI_Peregrinus wrote:
| The isolated environment is required because most Linux
| systems also depend upon Python, and can have dependency
| conflicts if you install development dependencies that
| conflict with system dependencies.
| dkarl wrote:
| The isolated environment can matter when different scripts
| that you use depend on libraries that have conflicting
| dependency requirements.
|
| > Competing languages like Java don't need or even have the
| concept of isolated environments
|
| The nice thing about scripts is that you can quickly add new
| capabilities when you need them. They are always under
| development. To get the same thing in Java, you need a
| project directory with a build file, which gives you an
| isolated build environment.
| simonw wrote:
| I think it's just good hygiene.
|
| If my weird one-off ad-hoc script needs numpy I can bake the
| exact tested version into an inline script dependency and run
| it with "uv run" and never have to think about it ever again.
|
| If I don't do that, there's a good chance that in a year I'll
| upgrade numpy for some other project and now my ad-hoc script
| will break.
|
| (Numpy is actually a great example here, lots of code I try to
| run turns out to need numpy 1.0 because it hasn't yet been
| upgraded to work with the new 2.0 - here's a recent example
| https://simonwillison.net/2024/Dec/24/modernbert/ )
| traverseda wrote:
| You can also do the same thing with the nix package manager and
| pretty much any language or dependency. Like if you wanted a
| portable bash-script with imagemagick #!
| /usr/bin/env nix-shell #! nix-shell -i bash -p bash
| imagemagick
|
| Handy for passing quick scripts around. Nothing is quite as
| portable as a single file like this.
| IshKebab wrote:
| > Nothing is quite as portable as a single file like this.
|
| Well... a file that doesn't require Nix is probably a fair bit
| more portable!
| traverseda wrote:
| Sure, an appimage, the UV example above
| nikkindev wrote:
| "Lazy self-installing Python scripts with uv"[1] article from
| Trey Hunner has more details with examples
|
| [1] https://treyhunner.com/2024/12/lazy-self-installing-
| python-s...
| godelski wrote:
| > For example, here's a script I use to print out 80 zeroes (or
| a specific number of zeroes)
|
| Also... # Print 80 0's and flush printf
| %.1s 0{1..80} $'\n' # Alternatively for i in
| {1..80}; do echo -n 0; done; echo
|
| For the ffmpeg example is this any different from
| ffmpeg -i in.mp4 -c:v copy -filter:a volumedetect -pass 1 -f
| null /dev/null &&\ ffmpeg -i in.mp4 -c:v copy -filter:a
| "loudnorm" -pass 2 out.mp4
|
| The python seems more complicated tbh
| EdwardDiego wrote:
| Not in any way relevant to an example of leveraging Python's
| new inline metadata PEP via uv.
| kseistrup wrote:
| See also https://news.ycombinator.com/item?id=42198256 from
| November 2024 (40 comments).
| PhilippGille wrote:
| From 68 days ago:
|
| "/usr/bin/env -S uv run":
| https://news.ycombinator.com/item?id=42198256
|
| 125 points, 45 comments
| d0mine wrote:
| to drop .py extension, you need to add `--script`
| babel_ wrote:
| Now that's a trick I should remember!
|
| I recently switched over my python aliases to `uv run python` and
| it's been really quite pleasant, without needing to manage
| `.venv`s and the rest. No fuss about system installs for python
| or anything else either, which resolves the old global/user
| install problem (and is a boon on Debian). Also means you can
| invoke the REPL within a project/environment without any
| `activate`, which saves needing to think about it.
|
| Only downside for calling a .py directly with uv is the cwd
| relative pathing to project/environment files, rather than
| relative to the .py file itself. There is an explicit switch for
| it, `--project`, which at least is not much of an ask (`uv run
| --project <path> <path>/script.py`), though a target relative
| project switch would be appreciated, to at least avoid the
| repetition.
| tiltowait wrote:
| I've seen uv a lot recently. Is there any major benefit over
| poetry?
| __mharrison__ wrote:
| Speed! You won't go back
| dave4420 wrote:
| Uv will manage python versions for you.
| ddorian43 wrote:
| That don't support compiled c/rust/etc libraries so you have
| to compile them.
| beaugunderson wrote:
| - great lock update behavior by default (though --no-update
| became the default in poetry 2.0)
|
| - speed, as others have said (5 minutes - 70 seconds for our
| docker build)
|
| - much easier (and faster) virtual environment management than
| poetry, should you want a venv
|
| - manages the python version, including new GIL-less variants
| if you want to try them
|
| - script dependencies (include requirements as a comment in a
| script and it will install and use them)
| xboxnolifes wrote:
| I've been using uv as a drop-in replacement for poetry. My
| little usage of it so far has led me to view it as just a
| better poetry. Does the same things I wanted from poetry, but
| faster and I haven't hit the dependency resolve issues I hit
| with poetry in the past (tbf, I think these got fixed in poetry
| since).
| mynegation wrote:
| It's way way faster for one.
| rav wrote:
| Oh wow, today I learned about env -S - when I saw the shebang
| line in the article, I immediately thought "that doesn't work on
| Linux, shebang lines can only pass a single argument". Basically,
| running foo.py starting with #!/usr/bin/env -S
| uv run --script
|
| causes the OS run really run env with only two arguments, namely
| the shebang line as one argument and the script's filename as the
| second argument, i.e.: /usr/bin/env '-S uv run
| --script' foo.py
|
| However, the -S flag of env causes env to split everything back
| into separate arguments! Very cool, very useful.
| sangeeth96 wrote:
| It's frustrating this is not the same behavior on macOS:
| https://unix.stackexchange.com/a/774145
| silverwind wrote:
| `brew install coreutils` and update your `PATH`.
| sangeeth96 wrote:
| I'm aware of this package for getting other utilities but:
|
| 1. I'm worried about this conflicting/causing other
| programs to fail if I set it on PATH. 2. This probably
| doesn't fix the shebang parsing issue I mentioned since
| it's an OS thing. Let me know if that's not the case.
| andreineculau wrote:
| You've got nothing to worry
|
| Been doing it for more than a decade and yet to get in
| trouble. Not one issue. Doing it consistently for my
| teams as we decrease cognitive load (developing on macs
| but targeting unix). Others would confirm
| https://news.ycombinator.com/item?id=17943202
|
| Basically software will either use absolute paths i.e.
| wants to use your OS version for a dependency like grep,
| or will use whatever grep is in your $PATH and stick to
| safe invocations regardless if it's BSD/GNU or if it's
| version x or y
| sangeeth96 wrote:
| Hmm, I haven't run this experiment myself but I have in
| the past faced problems overriding default python/ruby
| commands in PATH that caused some stuff to fail and had
| to add some specific overrides for `brew` command, for
| example.
|
| > Basically software will either use absolute paths
|
| I've personally written scripts that break this
| assumption (that's a me problem, I guess) so I am quite
| sure there's a lot of scripts at the very least that do
| this.
|
| Nevertheless, you've given me something to consider.
| 4ad wrote:
| The PATH is irrelevant, this is about how the kernel parses
| the shebang. It starts exactly /usr/bin/env with two
| arguments, not some other env binary you might have in your
| PATH.
| drzaiusx11 wrote:
| You can also brew install the gnu tools package and have
| both side by side for compatibility (gnu tools are prefixed
| with 'g', gls, gcat, etc
|
| I have a script that toggles the prefix on or off via bash
| aliases for when I need to run Linux bash scripts on a mac.
| rav wrote:
| It seems to me that macOS has env -S as well, but the shebang
| parsing is different. The result is that shebang lines using
| env -S are portable if they don't contain any quotes or other
| characters. The reason is that, running env -S 'echo a b c'
| has the same behavior as running env -S 'echo' 'a' 'b' 'c' -
| so simple command lines like the one with uv are still
| portable, regardless of whether the OS splits on space
| (macOS) or not (Linux).
| fjarlq wrote:
| This is true. For example, the following shebang/uv header
| works on both macOS and Linux:
| #!/usr/bin/env -S uv --quiet run --script # ///
| script # requires-python = ">=3.13" #
| dependencies = [ # "python-dateutil", # ]
| # /// # # [python script that needs dateutil]
| bas wrote:
| Very informative. Thank you!
| sangeeth96 wrote:
| True, this should be fine for straightforward stuff but
| extremely annoying as soon as you have for eg, quoted
| strings with whitespace in it which is where it breaks.
| Have to keep that difference in mind when writing scripts.
|
| The link I posted in my original reply has a good
| explanation of this behavior. I was the one who asked the
| question there.
| wink wrote:
| Maybe this helps? Have not tried it.
| https://blog.winny.tech/posts/multiple-arguments-in-shebang/
| dredmorbius wrote:
| And that on Android env doesn't live in /bin/.
| viraptor wrote:
| If the wrapper itself cooperates, you can also embed more
| information in the following lines. nix-shell for example
| allows installing dependencies and any parameters with:
| #!/usr/bin/env nix-shell #!nix-shell --pure -i runghc
| ./default.nix ... Any Haskell code follows
| __float wrote:
| Uv supports this:
| https://docs.astral.sh/uv/guides/scripts/#declaring-
| script-d...
|
| (Though, this is more general than uv for Python script deps:
| https://packaging.python.org/en/latest/specifications/inline.
| ..)
| IshKebab wrote:
| Yeah unfortunately support for that is kind of spotty, so don't
| do this in any scripts you want to work everywhere.
| mingus88 wrote:
| Yeah, my first reaction was cool, what's uv
|
| Oh, yet another python dependency tool. I have used a handful
| of them, and they keep coming
|
| I guess no work is important enough until it gets a super
| fast CLI written in the language du jour and installed by
| piping curl into sh
| kernelbugs wrote:
| I believe parent comment was about `env -S` not being
| portable rather than `uv` being portable.
|
| I'll say, I am as pessimistic as the next person about new
| ways to do X just to be hip. But as someone who works on
| many different Python projects day to day (from fully
| fledged services, to a set of lambdas with shared internal
| libraries, to CI scripts, to local tooling needing to run
| on developer laptops) - I've found uv to be particularly
| free of many sharp edges of other solutions (poetry,
| pipenv, pyenv, etc).
|
| I think the fact that the uv tool itself is not written in
| Python actually solves a number of real problems around
| bootstrapping and dependency management for the tool that
| is meant to be a dependency manager.
| bmitc wrote:
| > I think the fact that the uv tool itself is not written
| in Python
|
| It's interesting that the language people choose to write
| systems with (Python) is basically identified as not the
| best language to write systems to support that language
| (Python).
|
| To my knowledge, no other mainstream language has tooling
| predominantly written in another language.
| disgruntledphd2 wrote:
| gcc is written in C++ for like a decade now, so it's not
| completely unusual.
| bmitc wrote:
| It's a compiler for C, C++, and adjacent languages
| though.
| disgruntledphd2 wrote:
| Sure, but the point was a tool written in a different
| language. So the c part of gcc is another example of this
| issue.
| kloop wrote:
| I believe quite a bit of the JS tooling has been
| rewritten in other languages over the last decade or so
| HelloNurse wrote:
| It's important to use _any_ other language to avoid even
| the theoretical possibility of bootstrapping
| complications. All languages that produce self-contained
| compiled executables are equally suitable for the task.
| IshKebab wrote:
| Javascript has quite a lot of tooling written in other
| (better) languages.
|
| I think Javascript and Python stand out because they are
| both extremely popular and also not very good languages,
| especially their tooling. You're obviously going to get a
| load of people using Javascript and Python saying "why is
| Webpack/Pip so damn slow? I don't have any choice but to
| use this language because of the web/AI/my coworkers are
| idiots, so I may as well improve the tooling".
| IshKebab wrote:
| > Oh, yet another python dependency tool. I have used a
| handful of them, and they keep coming
|
| Yeah that's my opinion of all the other Python dependency
| tools, but uv is the real deal. It's fast, well designed,
| it's actually a drop-in replacement for pip and it actually
| works.
|
| > I guess no work is important enough until it gets a super
| fast CLI written in the language du jour and installed by
| piping curl into sh
|
| Yeah it's pretty nice that it's written in Rust so it's
| fast and reliable, and piping curl into sh makes it easy to
| install. Huge upgrade compared to the rest of Python
| tooling which is slow, janky and hard to install. Seriously
| the official way to install a recent Python on Linux is to
| build it from source!
|
| It's a shame curl | bash is the best option we have but it
| does at least work reliably. Maybe one day the Linux
| community will come up with something better.
| alt187 wrote:
| It's, er, "funny" how people used to make fun of `curl |
| sh` because of how lame it was, and now you have it
| everywhere because Rust decided that this should be the
| install.
| mixmastamyk wrote:
| There's a recent rust available in Fedora. That's what I
| use.
| benediktwerner wrote:
| You can also install rustup via your package manager and
| then use it as usual to manage your Rust installations.
| Though I guess in most cases, a single moderately recent
| Rust installation works just fine. But it's useful if you
| want/need to use Rust nightly for example.
| IshKebab wrote:
| > now you have it everywhere because Rust decided that
| this should be the install.
|
| No, now you have it everywhere because the Linux
| community completely failed to come up with anything
| better.
| tovej wrote:
| What do you mean? Linux has multiple excellent packaging
| solutions, apt/dpkg, yum, PKGBUILD/pacman
|
| If a developer can't be arsed to package their software,
| it's not the Linux community's fault
| baq wrote:
| uv is _the_ tool, finally. We 've been waiting for two
| decades and it really does basically everything right, no
| ifs or buts. You can scratch off the 'yet another' part.
| epcoa wrote:
| uv is not just a dependency tool. uv deals well with
| packages and dependency management (well), venvs, runtimes,
| and tools. It replaces all the other tools and works better
| in just about every way.
| nsteel wrote:
| What we have now, a load of different people developing a
| load of new (better!) tools, is surely what the PyPA had in
| mind when they developed their tooling standards. This is
| all going to plan. We've gotten new features and huge
| speedups far quicker this way.
|
| I don't like changing out and learning new tools
| constantly, but if this is the cost of the recent rapid
| tooling improvements then it's a great price.
|
| And best of all, it's entirely optional. You can even
| install it other ways. What exactly was your point here?
| gkfasdfasdf wrote:
| It would be nice if uv had something like uvx but for
| scripts...uvs maybe? Then you could put it as a single arg to
| env and it would work everywhere.
| sudahtigabulan wrote:
| Reminds me of how GNU Guile handles the one argument limitation
| - with "multi-line" shebang[1].
| #!/usr/bin/guile \ -e main -s !#
|
| turns into /usr/bin/guile -e main -s filename
|
| Wonder why they bothered.
|
| Probably env -S is a recent addition. Or not available on all
| platforms they cared about.
|
| [1]: https://www.gnu.org/software/guile/manual/html_node/The-
| Meta...
| RHSeeger wrote:
| Somewhat unrelated, I guess, but we used to use a split line
| shebang for tcl like the following
| #!/bin/sh # A Tcl comment, whose contents don't
| matter \ exec tclsh "$0" "$@"
|
| - The first line runs the shell
|
| - The second line is treated like a commend by the shell (and
| Tcl)
|
| - The third line is executed by the shell to run Tcl with all
| the command line args. But then Tcl treats it as part of the
| second line (a comment).
|
| Edit: Doing a bit of web searching (it's been a while since I
| last had the option to program in Tcl), this was also used to
| work around line length limitations in shebang. And also it
| let you exec Tcl from your path, rather than hard code it.
| moondev wrote:
| I like using this with tusk, which is a golang cli a bit like
| make, but it uses yaml for the config. The shebang is
| #!/usr/bin/env -s go run github.com/rliebz/tusk@latest -f
|
| Then use gosh a golang shell for the interpreter
| interpreter: go run mvdan.cc/sh/v3/cmd/gosh@latest -s
|
| This makes it a cli can run anywhere on any architecture with
| golang installed
| MayeulC wrote:
| Yeah, it is very useful and allows environment variables, so
| you can do /usr/bin/env -S myvar=${somevar}
| ${someprefix}/bin/myprogram
|
| However, as another commenter wrote, support is not universal
| (looks present in RH8 but not RH7 for instance). Also, the max
| length of a shebang is usually limited to about 127 characters.
|
| So sometimes you have to resort to other tricks, such as
| polyglot scripts: /usr/bin/sh """exec"
| python --whatever "$@" Well this is still a Python
| docstring """ print("hello")
|
| Or classically in Tcl: #! /usr/bin/sh #
| Tcl can use \ to continue comments, but not sh \ exec
| tclsh "$@" # still a comment in Tcl puts "hello"
|
| Such things are not usually needed, until they are, and they
| make for fun head-scratching moment. I would personally
| recommend against them if they can be avoided, as they are
| relatively fragile.
|
| I'll leave the self-compiling C language script "shebang" as an
| exercise to the reader ;)
| quotemstr wrote:
| env -S should never have been necessary. The strange whitespace
| splitting rules of the shebang line is an old bug that has
| matured into an unfixable wart marring the face of Unix
| forever. Every time I have to use tricks like the above, I'm
| reminded that half an hour of work in the 1980s would have
| saved years of annoyance later. Shebang lines should have
| always split like /bin/sh.
| oneshtein wrote:
| Send your patches to Linux and BSD kernel mailing lists.
| tiberriver256 wrote:
| uv makes Python actually usable. Freaking love that tool.
| 7thpower wrote:
| Does anyone have any intro to UV guides they found helpful?
|
| I haven't dove into uv as it just hasn't been at the top of my
| list, but I will probably take the plunge soon.
|
| I gave it an initial try thinking it might function as a drop in,
| but didn't find any great guides, and just haven't been back yet.
| But we're ~8% into 2025 so it's time.
| picafrost wrote:
| Astral are making great tools. There are many points of friction
| in the Python world and Astral is making them seem obvious to see
| and obvious to solve. That is hard work.
| dcre wrote:
| For the TypeScript enjoyers: you can do the same with Deno (and
| I'm sure Bun too, though I haven't done it). #!
| /usr/bin/env -S deno run
|
| You can add permission flags like this: #!
| /usr/bin/env -S deno run --allow-env --allow-read --allow-net
| IshKebab wrote:
| I love Deno and I use this, but I really wish they would fix
| this dumb bug:
|
| https://github.com/denoland/deno/issues/16466
| sebmellen wrote:
| I really wish they would allow you to connect to "unsafe" TLS
| endpoints.
|
| https://github.com/denoland/deno/issues/6427#issuecomment-65.
| ..
| tempaccount420 wrote:
| Jesus, both of these issues are sad. This is probably why
| Bun is winning
| sebmellen wrote:
| Just absolutely infuriating to work with. We migrated all
| of our RPA scripts to Deno and then this popped up and
| killed our hopes and dreams.
|
| > "What, you want to connect to an old government website
| that has an old TLS version? You are a very bad boy. Not
| allowed!"
|
| Back to Node we go.
| IshKebab wrote:
| Yeah definitely a case of "you're holding it wrong".
| Never a good look.
| dcre wrote:
| That's interesting! I think I've run into it but it has
| rarely been a problem.
| mkl wrote:
| Related article and discussion from 16 days ago: Uv's killer
| feature is making ad-hoc environments easy
| https://news.ycombinator.com/item?id=42676432 (502 points, 417
| comments)
| TrueDuality wrote:
| One gotcha that annoys me when do this... The file still needs to
| end in .py which I generally don't like for the bins and
| utilities in my path. Everyone using these shebangs either
| doesn't hit this or never mentions it. Entirely a stylistic
| personal preference but still makes me a sad lady.
| puzzledobserver wrote:
| Are you sure about this?
|
| I just wrote a script without a .py extension, and it seemed to
| work fine.
| d0mine wrote:
| `--script` has been added to fix it https://github.com/astral-
| sh/uv/issues/6360#issuecomment-245...
| infogulch wrote:
| Speaking of funny shebangs, I came up with this to shell execute
| prolog .pl files, but it should work for any scripting language
| that has /**/-comments but doesn't support #-comments or #!
| shebangs specifically: /*usr/bin/env scryer-
| prolog "$0" "$@" ; exit #*/
|
| From my original comment https://github.com/mthom/scryer-
| prolog/issues/2170#issuecomm... :
|
| > The way this works is that this test.pl is both a valid shell
| file and prolog file. When executing as shell the first line
| finds and executes /usr/bin/env after searching for the glob
| pattern /*usr/bin/env. env then executes scryer-prolog "test.pl"
| which runs the prolog file as a module and halts; of course
| prolog ignores the first line as a comment /* ... */. Then the
| shell continues and executes the next command after ; which is
| exit which stops execution so the rest of the file (which is not
| valid shell) is ignored. The # makes the shell evaluator ignore
| prolog comment closer */ to prevent it from printing an error.
|
| This may be the best and worst thing I have ever created.
| upghost wrote:
| Oh my god this is amazing. We need to fix some of the IO
| redirect in Scryer and then this will be a perfect replacement
| for bash scripts <3
|
| You rock!
| emmelaich wrote:
| Similarly, make go source executable :
| https://unix.stackexchange.com/questions/162531/shebang-star...
|
| also, my contribution, make C programs executable:
| $ cat cute-use-of-slash-slash.c //usr/bin/env sh -c
| 'p=$(expr '"_$0"' : "_\(.*\)\.[^.]*"); make $p > /dev/null &&
| $p'; exit #include <stdio.h> int
| main() { puts("hello world"); }
| $ chmod +x cute-use-of-slash-slash.c $ ./cute-use-of-
| slash-slash.c hello world $ $(pwd)/cute-use-of-
| slash-slash.c hello world $ ../cc/cute-use-of-
| slash-slash.c hello world $ sed -i -e
| s/hello/bye/ cute-use-of-slash-slash.c $ ./cute-use-of-
| slash-slash.c bye world $
| mzs wrote:
| I didn't think of this but I use it: %
| ./hworld.tcl Hello, world. % cat hworld.tcl
| #!/bin/sh # the next line restarts using tcl \ exec
| tclsh "$0" "$@" puts "Hello, world." %
|
| Turns-out that in TCL you can line continue a comment :)
| Levitating wrote:
| Ruby's bundler has actually always been able to do inline
| dependencies
|
| https://bundler.io/guides/bundler_in_a_single_file_ruby_scri...
|
| Though I think the implementation could be improved upon
| anotherpaulg wrote:
| Not using shebang, but I've recently been using uv as an
| "installer". It's hard to package and distribute python CLI tools
| with complex dependencies. I used uv in a couple of novel ways:
|
| 1. I copied their `curl | sh` install script and added a `uv tool
| install --python python3.12 my-tool` line at the end. So users
| can now install my CLI tool with a nice curl-pipe-sh one-liner.
|
| 2. I made a tiny pypi "installer" package that has "uv" as its
| only dependency. All it does is `uv tool install` my CLI tool.
|
| Both methods install the CLI tool, python3.12 and all python
| dependencies in their own isolated environment. Users don't need
| to manage python virtual envs. They don't need to even have
| python installed for the curl-pipe-sh method.
|
| I now get far fewer GitHub issues from users who have somehow
| mangled the complex dependencies of my tool.
|
| I wrote it up with more detail and links to code:
|
| https://aider.chat/2025/01/15/uv.html
| CoolCold wrote:
| I have not checked how that works under the hood, but
|
| > Both methods install the CLI tool, python3.12
|
| Won't that require some compiler (GCC?), kernel headers,
| openssl-dev/gzip/ffi/other_lib headers to be present on end
| user system and then compiling Python?
|
| At least that's my experience with ASDF-VM, which uses
| someother Python-setup toolkit under the hood.
| Zizizizz wrote:
| https://docs.astral.sh/uv/concepts/python-
| versions/#cpython-... it has pre-compiled versions
| oulipo wrote:
| Nice! I think `mise` and `aqua` also have a notion of tool
| install which can be useful
| alin23 wrote:
| I recently learned about swift-sh [1] which is the same thing as
| "uv run --script" but for swift files.
|
| I've been having a blast automating some macOS annoyances with
| small scripts that can use native macOS APIs directly, no more
| pyobjc.
|
| I also wrote an app to bring the startup folder functionality
| from Windows to the Mac to help me run these scripts at startup
| more easily [2]
|
| [1] https://github.com/mxcl/swift-sh
|
| [2] https://github.com/FuzzyIdeas/StartupFolder
| Tyrubias wrote:
| I love using this technique, but developing these scripts has
| always bothered me because there's no code completion without an
| actual `venv` to point my editor to. Has anyone found a way
| around this?
| mixmastamyk wrote:
| Try pointing to --user, aka ~/.local/lib/python3.??/site-
| packages
| Eduard wrote:
| why not #!/usr/bin/env python3 ?
| mynegation wrote:
| That works reliably for scripts that use standard library only
| and you also have to be careful not to use features
| incompatible with various minor versions of Python 3.
| m3at wrote:
| Uv's support of inline metadata is super handy. What if the
| person running the scripts doesn't have uv yet though? For fun I
| wrote a double shebang script that will handle that too:
| https://paulw.tokyo/standalone-python-script-with-uv/
| AdieuToLogic wrote:
| This reminds me of an old Perl magic spell for invoking it within
| a Bourne/POSIX shell wrapper along with allowing arbitrary
| command line arguments[0]: #!/bin/sh #! -*-
| perl -*- -p eval 'exec perl -x -wS $0 ${1+"$@"}' if
| 0; # It's Perl code from this point.
|
| 0 - https://perldoc.perl.org/perlrun
| recursive_fruit wrote:
| Oh nice, that's really cool. I'm seeing uv pop up in more and
| more places. Python really needed this tooling upgrade. Also,
| I'll make a mental note of -S, awesome.
|
| If you want to do the same with javascript or typescript, you can
| just use bun, it will auto-install[1] the packages included in
| there. #!/usr/bin/env bun
|
| [1]: https://bun.sh/docs/runtime/autoimport
| zombot wrote:
| What is this `uv` thing? Is that something pythonic?
| zrail wrote:
| > An extremely fast Python package and project manager, written
| in Rust.
|
| https://github.com/astral-sh/uv
| megamix wrote:
| if it has Rust in it, then...
| mark_l_watson wrote:
| Nice ideas, especially with "-S" env option.
|
| I love having little custom command line apps in my ~/bin
| directory. I used to, a very long time ago, use Gambit Scheme for
| this, then moved on to Common Lisp command line apps. More
| recently I have been using Python for ~/bin scripts but since I
| use venv for each individual project on my laptop, having a
| global Python setup with dependencies for ~/bin is annoying.
| Using uv seems like a great idea, which I will try today: use uv
| for all command line apps and venv for all other Python coding
| projects.
___________________________________________________________________
(page generated 2025-01-29 23:02 UTC)