Sbang lets you run scripts with long shebang lines
github.com
github.com
`env -S` introduces an option parser/splitter for #!-lines which can do just about whatever you need (however, it will not work around over-long lines like sbang proposes to do)
#!/usr/bin/env -S perl -w -T
Why is the `/usr/bin/env -S` even in there? Why not rather #!perl -w -T
I know that not all environments support non-absolute paths to interpreters like this, but it feels to me that adding -S to env is a worse hack than allowing non-absolute paths to interpreters. I’m not sure which platforms support resolving the interpreter by PATH (actually, is supporting it a shell thing?), but it may even be more portable than -S at present, GNU coreutils env only having had it for two years. And even /usr/bin/env itself isn’t fully portable, as there are (old) platforms that have env at /bin/env and not /usr/bin/env. # cat test.py
#!/usr/bin/python3
import sys
print(sys.argv)
$ cat test
#!/usr/bin/env test.py foo bar baz
$ PATH=. ./test
/usr/bin/env: 'test.py foo bar baz': No such file or directory
/usr/bin/env: use -[v]S to pass options in shebang lines
with -S, env does the right thing, and you get this: $ cat test
#!/usr/bin/env -S test.py foo bar baz
$ PATH=. ./test
['./test.py', 'foo', 'bar', 'baz', './test']This:
#!python3
Seems to work (i.e., search $PATH) on macos but AFAIK nowhere else. It fails on both ubuntu20 and centos8. Per this: https://www.in-ulm.de/~mascheck/various/shebang/, relative paths are supposed to be interpreted as relative to ., so I'm guessing that is why everyone uses /usr/bin/env.Given that shebang is implemented in the kernel (and not in user-space like coreutils) I think env is more likely to change than the shebang mechanism, though who knows -- there have been recent changes to shebang so perhaps further work on this will help: https://lwn.net/Articles/779997/.
We want installed packages to work exactly as built, with the right versions of dependencies, and we don't want to rely on the user getting their environment right to do that. Spack users may install several versions of python or other interpreters. This ensures that scripts work without a special environment.
There is another use case that is less emphasized here. sbang also lets you pass arbitrarily many arguments on the shebang line. If you do this:
#!/usr/bin/perl arg1 arg2 arg3
At least on Linux, you'll get one argument: "arg1 arg2 arg3". I think perl gets around this by parsing the shebang line itself, but sbang is more general. You can use it with /usr/bin/env to pass more arguments than would otherwise be allowed.See https://www.in-ulm.de/~mascheck/various/shebang/ for an extremely comprehensive list of limitations on shebangs.
Most often when calling programs with a shell script it is recommended to make use of env to find it.
Like...
#!/usr/bin/env python3
As in the limitations link above, env is pretty much everywhere, and when it isn't, you're probably going to struggle anyway to make anything portable to those systems.env actually has an in-built flag for ensuring you're passing arguments.
#!/usr/bin/env -S python3 -m http.server 8010- you still get the python3 in PATH, not a specific one (sbang aims to use a specific interpreter)
- The -S argument to env is not POSIX: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/e...
env lets you solve that one too. You can control PATH. From the FreeBSD manpages:
#!/usr/bin/env -S -P/usr/local/bin:/usr/bin perl
And if you lack the -P flag... env controls the environment variables... So, you could extend (or replace) it like so: #!/usr/bin/env PATH=/home/my/loc:${PATH} perl
> The -S argument to env is not POSIXYou're right. POSIX only guarantees the -i flag, and the ability to set variables. It hasn't been modified in the standard since 1991, despite other updates to the standard.
OpenBSD and Busybox only supports the crippled POSIX version. It isn't completely portable.
Versions with -S and are available on Linux, FreeBSD (also has -P), macOS (also has -P).
This is probably obvious but bears repeating since we're on this tangent -- even -S and -P do not prevent the OS from truncating the shebang if it's too long. So env is great for passing multiple args, but it still doesn't let you use really long shebangs (the original point of the thread :)
#!/bin/bash
/some/long/path with lots of argsI'd like to invoke them with just (eg.) ./dostuff.py - Python, Ruby etc... have absolutely no problem running files containing Win-style line-endings. The only issue is that /usr/bin/env complains that it can't find (eg.) "python3\n".
Yes, I know I could convert these files with dos2unix, and I also know that I can just invoke the interpreter explicitly - but I'm lazy, and this seems like such a trivial thing to solve that I can't believe it's not been done already.
I've taken to actually recompiling /usr/bin/env to strip trailing whitespace from the executable name - but there must be a better solution.
Better, yes. Easy, no. Impossible is a sort timeframe, probably (given how many systems are out there not confirming to this as yet undecided standard).
Maybe that will actually happen long-term, with this being essentially a polyfil.