- The thing that surprised me was that you can't write an interpreter in an interpreted language, at least not in obsd. It is possible if you jump through a few hoops but you can't directly call it.
An example: if you made a language in python
/bin/my_lang: #does nothing but pretend it does
#!/usr/local/bin/python3
import sys
print('my_lang args', sys.argv)
for line in sys.stdin:
print('invalid_line:', line)
my_script: #!/bin/my_lang
line of stuff
another line of stuff
chmod u+x my_script
./my_script
Probably for the best, but I was a bit sad that my recursive interpreter scheme was not going to work.Update: looks like linux does allow nested interpreters, good for them.
https://www.in-ulm.de/~mascheck/various/shebang/#interpreter...
really that whole document is a delightful read.
- 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 every day I guess.
- Hit the link expecting to read about UTF-8 Byte Order Marks at the top of the file, so that the first few bytes aren't actually #! but 0xEF 0xBB 0xBF #! instead. Ran into this one just a few months ago when a coworker who uses Windows had checked a Bash script into the Git repo. His editor was configured to save files as "UTF-8 with BOM" and so we were getting errors that looked like "./doit.sh: line 1: #!/bin/bash: No such file or directory". Can you see the invisible BOMb in that line? It's there, I promise you.
That's not what the article was actually about, as it turned out. The surprise in the article was about relative paths for script shebang lines. Which was useful to learn about, of course, but I was actually surprised by the surprise.
- > 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 to gain in disallowing the program path on the shebang line to be relative. The person that wrote the shebang can also write relative paths in some other part of the file.
- 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.
- What's suprised me is that there is a line length limit on #! for 256 bytes.
You can have spacing after #! for some reason?
POSIX does not mandate -S, which means any script that uses it will only work on freebsd/linux
- Historically FreeBSD used to split the #! argument list fully which meant you could put oneline scripts in there. At some point too many ports had to struggle with Linuxisms that this was changed to only split it into command and first argument. The old behaviour can be accessed with a flag in the env wrapper.
by p4cmanus3r
4 subcomments
- 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 <whatever>' 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 '<whatever>' in different places, which is probably most common for third party packages)."
His very first point is how you should only use it don't know where to expect bash binary, when I feel like, while it's probably safe in most nix os', assuming it limits future enhancements by requiring that binary be in place. However unlikely it would need to or someone would want to move it.
- Kind of an adjacent aside, I kind of love how many languages now work with shebangs for creating user scripts... Go, Rust, C#, Deno (TS/JS) etc.
The vast majority of my shell/user scripts are now in TS with Deno... The only thing I do wish worked better is that VS Code would look at the shebang to determine a file's language without a file extension.
Also works nicely with project automation and CI/CD integration as well... You can do a lot more, relatively easier than having to have knowledge of another language/tool you aren't as comfortable with.
by userbinator
3 subcomments
- I wonder what the reason was for having the kernel handle this, instead of the shell? To allow programs besides the shell to execute interpreted scripts as if they were actual binaries?
This is of course in stark contrast to dynamic linking, which is performed by a userspace program instead of the kernel, and much like the #!, this "interpreter"'s path is also hardcoded in dynamically linked binaries.
- For personal use, I used to write #!perl to avoid the hassle of keeping track of the location of the binary across differing systems (although now I wonder if this only worked in the shell I ran under WinNT4—it’s been ages since I’ve done that sort of thing and these days I tend not to use #! at all to run scripts.)
- There's no security issue here. Certainly the OP hasn't explained why there is one.
by 1718627440
2 subcomments
- > You're using a suspiciously old browser
Does the author not like Firefox or what?
- more/older https://www.in-ulm.de/~mascheck/various/shebang/
by coppsilgold
1 subcomments
- There is no security issue here. The file with the '#!' needs to be executable, and at that point it doesn't matter what it invokes because you made it executable. It could have shellcode in it or it could call python3 which can also execute shellcode. Or more likely, it would just be a malware binary which you deliberately gave permissions to and executed.
- This insight came from perl5 btw.