top | item 42856610

(no title)

rav | 1 year 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.

discuss

order

sangeeth96|1 year ago

It's frustrating this is not the same behavior on macOS: https://unix.stackexchange.com/a/774145

rav|1 year ago

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).

silverwind|1 year ago

`brew install coreutils` and update your `PATH`.

dredmorbius|1 year ago

And that on Android env doesn't live in /bin/.

sudahtigabulan|1 year ago

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|1 year ago

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|1 year ago

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

viraptor|1 year ago

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

quotemstr|1 year ago

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.

Ferret7446|1 year ago

If 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.

oneshtein|1 year ago

Send your patches to Linux and BSD kernel mailing lists.

MayeulC|1 year ago

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 ;)

IshKebab|1 year ago

Yeah unfortunately support for that is kind of spotty, so don't do this in any scripts you want to work everywhere.

gkfasdfasdf|1 year ago

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.

mingus88|1 year ago

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