6 ms·
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 pas
by rav 2y ago
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 2y agoIt's frustrating this is not the same behavior on macOS: https://unix.stackexchange.com/a/774145 https://unix.stackexchange.com/a/774145
- silverwind 2y ago`brew install coreutils` and update your `PATH`.
- sangeeth96 2y agoI'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 2y agoYou'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 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 2y agoHmm, 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 2y agoThe 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 2y agoYou 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 2y agoIt 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 2y agoThis 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 2y agoVery informative. Thank you!
- sangeeth96 2y agoTrue, 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 2y agoMaybe this helps? Have not tried it. https://blog.winny.tech/posts/multiple-arguments-in-shebang/ https://blog.winny.tech/posts/multiple-arguments-in-shebang/
- dredmorbius 2y agoAnd that on Android env doesn't live in /bin/.
- viraptor 2y agoIf 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 2y agoUv supports this: https://docs.astral.sh/uv/guides/scripts/#declaring-script-dependencies 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-script-metadata/#script-type https://packaging.python.org/en/latest/specifications/inline...)
- IshKebab 2y agoYeah unfortunately support for that is kind of spotty, so don't do this in any scripts you want to work everywhere.
- mingus88 2y agoYeah, 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 2y agoI 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 2y ago> 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 2y agogcc is written in C++ for like a decade now, so it's not completely unusual.
- sudahtigabulan 2y agoReminds 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-Switch.html https://www.gnu.org/software/guile/manual/html_node/The-Meta...
- RHSeeger 2y agoSomewhat 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 2y agoI 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 2y agoYeah, 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 2y agoenv -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 2y agoSend your patches to Linux and BSD kernel mailing lists.
- quotemstr 2y agoIt cannot be fixed now. It would break thing.
- Ferret7446 2y agoIf you need more than what shebang allows, you're probably better off writing a regular shell script and doing whatever you need in shell IMO.