Live data from Hacker News

A surprise with how '#!' handles its program argument in practice

utcc.utoronto.ca

71–80 of 116 posts

Re: A surprise with how '#!' handles its program argument in practice

#71
post #50
post #48

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.

Keep in mind that the bash you get on MacOS is bash 3.2 released in 2006 so relying on it for portability might not be a good idea.

Re: A surprise with how '#!' handles its program argument in practice

#72
post #65

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

[deleted]

Re: A surprise with how '#!' handles its program argument in practice

#73
post #25
post #23

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

/bin/sh is part of the POSIX standard -- even NixOS puts a symlink there.

Re: A surprise with how '#!' handles its program argument in practice

#75
post #66

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

If you're okay with running the script only from the parent directory of the venv (I guess you have things set up so that's the project root), fine.

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

#77

The 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…

Never thought of it this way; isn’t it always safe to assume env is in PATH?

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

#78
post #54
post #15

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

> /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

#79
post #55

This insight came from perl5 btw.

See also the perlrun documentation[0].

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#-S

Re: A surprise with how '#!' handles its program argument in practice

#80
post #23

Earlier 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…

[deleted]
Post reply on HN