Live data from Hacker News

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

utcc.utoronto.ca

11–20 of 116 posts

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

#11
post #3

Earlier quoted context omitted.

Seems like it only works in zsh, not bash or fish

The kernel interprets the shebang line, not the shell.

It is possible for the shell to handle it. From zshall(1):

> If the program is a file beginning with ‘#!', the remainder of the first line specifies an interpreter for the program. The shell will execute the specified interpreter on operating systems that do not handle this executable format in the kernel.

Taking a quick look at the source in Src/exec.c:

  execve(pth, argv, newenvp);
  // [...]
  if ((eno = errno) == ENOEXEC || eno == ENOENT) {
              // [...]
              if (ct >= 2 && execvebuf[0] == '#' && execvebuf[1] == '!') {
                                // [...]
                                (pprog = pathprog(ptr2, NULL))) {
I guess at some point someone added that `|| eno == ENOENT` and the docs weren't updated.

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

#12
post #2

Huh. I wish I had known this before. NixOS is annoying because everything is weird and symlinked and so I find myself fairly frequently making the mistake of writing `#!/bin/bash`, only to be told it can't find it, and I have to replace the path with `/run/current-system/sw/bin/bash`. Or at least I thought I did; apparently I can just have done `#!bash`. I just tested this, and it worked fine. You learn something new…

You can use `#!/usr/bin/env bash` on NixOS

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

#13
post #3

Earlier quoted context omitted.

Seems like it only works in zsh, not bash or fish

The kernel interprets the shebang line, not the shell.

I'm not sure the reason then, but they're definitely right; it works fine with zsh, doesn't work with bash. I wrote a test script to try it myself.

I don't have fish installed and can't be bothered to go that far, but I suspect they're right about that as well.

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

#14
post #2

Huh. I wish I had known this before. NixOS is annoying because everything is weird and symlinked and so I find myself fairly frequently making the mistake of writing `#!/bin/bash`, only to be told it can't find it, and I have to replace the path with `/run/current-system/sw/bin/bash`. Or at least I thought I did; apparently I can just have done `#!bash`. I just tested this, and it worked fine. You learn something new…

`#!/usr/bin/env bash` is the most portable form for executing it from $PATH

Is this meaningfully more portable than #!bash though?

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

#15
post #2

Huh. I wish I had known this before. NixOS is annoying because everything is weird and symlinked and so I find myself fairly frequently making the mistake of writing `#!/bin/bash`, only to be told it can't find it, and I have to replace the path with `/run/current-system/sw/bin/bash`. Or at least I thought I did; apparently I can just have done `#!bash`. I just tested this, and it worked fine. You learn something new…

You can use `#!/usr/bin/env bash` on NixOS

I didn't know that actually. I'll start using that from this point forward.

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

#16

Earlier quoted context omitted.

`#!/usr/bin/env bash` is the most portable form for executing it from $PATH

Is this meaningfully more portable than #!bash though?

In a sibling thread someone pointed out that #!bash doesn't actually work if you're calling it from bash, and appears to only work with zsh.

I just tried it and they were absolutely right, so `#!/usr/bin/env bash` is definitely more portable in that it consistently works.

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

#17
post #13

Earlier quoted context omitted.

The kernel interprets the shebang line, not the shell.

I'm not sure the reason then, but they're definitely right; it works fine with zsh, doesn't work with bash. I wrote a test script to try it myself. I don't have fish installed and can't be bothered to go that far, but I suspect they're right about that as well.

env bash is all well and good for normies, but if you're already on NixOS did you know you can have nix-shell be your interpreter and back flip into any reproducible interpreted environment you like?

https://nixos.wiki/wiki/Nix-shell_shebang

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

#18
post #4

> Although this is probably the easiest way to implement '#!' inside the kernel, I'm a little bit surprised that it survived in Linux (in a completely independent implementation) and in OpenBSD (where the security people might have had a double-take at some point). But given Hyrum's Law there are probably people out there who are depending on this behavior so we're now stuck with it. I don't see what there would be t…

Or, like, if you aren't reading and caring about what the interpreter is--as that's the only time this can burn you: it isn't doing a PATH lookup, so you can't walk into this one on accident--then it could literally be something like /bin/rm on some key file. This entire article is based on an assumption that this is somehow so obviously bad that there doesn't even need to be an explanation or defense of any kind of that idea.

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

#19

Earlier quoted context omitted.

`#!/usr/bin/env bash` is the most portable form for executing it from $PATH

Is this meaningfully more portable than #!bash though?

This mechanism doesn't do a PATH lookup: #!bash would only work if bash was located in your current working directory.

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

#20
post #2

Huh. I wish I had known this before. NixOS is annoying because everything is weird and symlinked and so I find myself fairly frequently making the mistake of writing `#!/bin/bash`, only to be told it can't find it, and I have to replace the path with `/run/current-system/sw/bin/bash`. Or at least I thought I did; apparently I can just have done `#!bash`. I just tested this, and it worked fine. You learn something new…

Anything other than ”#!/usr/bin/env bash” is doomed to fail at some time.

And is this shebang guaranteed to work always? Why isn't it more common?
Post reply on HN