Earlier quoted context omitted.
/bin is the "standard" location for bash on a subset of Linux distributions and basically no other Unix... So it's not really a standard. /bin/sh is a much more common convention but once again, not a standard. There really isn't a truly portable shebang, but the same can be said about executables themselves. As part of the build or install step of whatever thing you're making, you should really be looking these up a…
> /bin is the "standard" location for bash on a subset of Linux distributions and basically no other Unix... You’re forgetting macOS. It has been using /bin/bash forever.
A surprise with how '#!' handles its program argument in practice
71–80 of 116 posts
Re: A surprise with how '#!' handles its program argument in practice
#72Earlier quoted context omitted.
Wait... your interpreter reads from stdin. Shouldn't it read its first arg, instead?
IIRC interpreters can also read their programs from stdin. Try piping a script to bash and see if it works. (Actually, this is how the `curl install.sh | bash` anti pattern works. )
Re: A surprise with how '#!' handles its program argument in practice
#73Earlier quoted context omitted.
Because /bin is the standard location for bash. The only one that breaks that expectation is NixOS (and maybe GuixSD?), apparently. I'm surprised they didn't symlink /bin or put a stub. Last time I tried NixOS was like 10 years ago. I thought there was a /bin/bash, but maybe it was just a /bin/sh? Other interpreters like python, ruby, etc. have more likelyhood of being used with "virtual environments", so it's more c…
They do symlink /bin/sh to be fair, and that's very often good enough for a lot of scripts. That's what I usually do if I don't need anything bash offers.
Re: A surprise with how '#!' handles its program argument in practice
#74Re: A surprise with how '#!' handles its program argument in practice
#75I do this all the time for python virtualenvs. Instead of calling ‘#!/usr/bin/env python3’ I will call ‘#!venv/bin/python3’. This way I don’t have to worry about whether the environment was activated or not.
You never have to "worry about whether the environment was activated", unless your code depends on those environment variables (in which case your shebang trick won't help you). Just specify the path to the venv's Python executable.
You aren't really intended to put your own scripts in the venv's bin/ directly, although of course you can. An installer will create them for you, from the entry points defined in pyproject.toml. (This is one of the few useful things that an "editable install" can accomplish; I'm generally fairly negative on that model, however.)
If you have something installed in a venv and want to run it regardless of CWD, you can symlink the wrapper script from somewhere on your PATH. (That's what Pipx does.)
Re: A surprise with how '#!' handles its program argument in practice
#76> You're using a suspiciously old browser Does the author not like Firefox or what?
Re: A surprise with how '#!' handles its program argument in practice
#77The authors previous article about "...(not) using #!/usr/bin/env whatever" doesn't sit well with me. "The only reason to start your script with '#!/usr/bin/env ' is if you expect your script to run on a system where Bash or whatever else isn't where you expect (or when it has to run on systems that have ' ' in different places, which is probably most common for third party packages)." His very first point is how you…
Maybe `#! env ` could be considered a DSL for hashbangs. My reasoning is that `/usr/bin/env` is the thing that seems to be hard-coded to a system path, in most cases.
Re: A surprise with how '#!' handles its program argument in practice
#78Earlier quoted context omitted.
I didn't know that actually. I'll start using that from this point forward.
/usr/bin/env and /bin/sh are part of the POSIX standard, this is why NixOS has those available.
Contrary to popular belief, those aren't in the POSIX standard.
The following are not in the POSIX standard, they are just widely implemented:
- "#!" line.
- /bin/sh as the location of a POSIX compliant shell, or any shell.
- /usr/bin/env as the location of an env program.
- The -S option to env.Re: A surprise with how '#!' handles its program argument in practice
#79This insight came from perl5 btw.
This example works on many platforms that have a shell compatible with Bourne shell:
#!/usr/bin/perl
eval 'exec /usr/bin/perl -wS $0 ${1+"$@"}'
if 0; # ^ Run only under a shell
The system ignores the first line and feeds the program to /bin/sh, which proceeds to try to execute the Perl program as a shell script. The shell executes the second line as a normal shell command, and thus starts up the Perl interpreter. On some systems $0 doesn't always contain the full pathname, so the "-S" tells Perl to search for the program if necessary. After Perl locates the program, it parses the lines and ignores them because the check 'if 0' is never true. If the program will be interpreted by csh, you will need to replace ${1+"$@"} with $*, even though that doesn't understand embedded spaces (and such) in the argument list. To start up sh rather than csh, some systems may have to replace the #! line with a line containing just a colon, which will be politely ignored by Perl. Other systems can't control that, and need a totally devious construct that will work under any of csh, sh, or Perl, such as the following: eval '(exit $?0)' && eval 'exec perl -wS $0 ${1+"$@"}'
& eval 'exec /usr/bin/perl -wS $0 $argv:q'
if 0; # ^ Run only under a shell
[0]: https://perldoc.perl.org/perlrun#-SRe: A surprise with how '#!' handles its program argument in practice
#80Earlier quoted context omitted.
And is this shebang guaranteed to work always? Why isn't it more common?
Because /bin is the standard location for bash. The only one that breaks that expectation is NixOS (and maybe GuixSD?), apparently. I'm surprised they didn't symlink /bin or put a stub. Last time I tried NixOS was like 10 years ago. I thought there was a /bin/bash, but maybe it was just a /bin/sh? Other interpreters like python, ruby, etc. have more likelyhood of being used with "virtual environments", so it's more c…