#+title: Shebang
#+date: <2023-04-16 Sun 11:15>
#+author: thebesttv

- The bible of shebang interpretations:
  [[https://www.in-ulm.de/~mascheck/various/shebang/][The =#!= magic, details about the shebang/hash-bang mechanism on various Unix flavours]]

* Splitting arguments

According to [[https://linuskarlsson.se/blog/shebang-shenanigans/#summary][Shebang Shenanigans]] and [[https://www.in-ulm.de/~mascheck/various/shebang/#splitting][section splitting arguments]],
when it comes to multiple arguments after shebang, different systems
interpret then differently.  For example:
#+begin_src sh
  #!/usr/local/bin/args -a -b --something
#+end_src
Linux treats =-a -b --something= as a single argument.  MacOS treats
them as 3 separate arguments.  Some other systems may even pass =-a= as
a single argument and discard the rest.

Also, from [[https://jhermann.github.io/blog/linux/know-how/2020/02/28/env_with_arguments.html][this article]], in the bash document:
#+begin_quote
If the program is a file beginning with =#!=, the remainder of the first
line specifies an interpreter for the program.  ...  The arguments to
the interpreter consist of *a single optional argument* following the
interpreter name on the first line of the program, followed by the name
of the program, followed by the command arguments, if any.
#+end_quote
Note here, *a single optional argument*.

** =env -S= to the rescue

According to [[https://unix.stackexchange.com/a/477651][this answer]], starting with coreutils 8.30, you can use:
#+begin_src sh
  #!/usr/bin/env -S command arg1 arg2 ...
#+end_src
The =-S/--split-string= option enables use of multiple arguments in
shebang.

** An example

First, write a simple Python script for displaying arguments:
#+begin_src python
  #!/usr/bin/env python

  import sys
  for i, arg in enumerate(sys.argv):
      print(f"{i}: {arg}")
#+end_src
Store it under =/tmp/showargs= and make it executable.
Test the script:
#+begin_src bash
  $ /tmp/showargs single 'one long arg' another single
  0: /tmp/showargs
  1: single
  2: one long arg
  3: another
  4: single
#+end_src

If the shebang calls =showargs= directly, the arguments are merged into
one:
#+begin_src bash
  $ cat go
  #!/tmp/showargs single 'one long arg' another single
  $ ./go
  0: /tmp/showargs
  1: single 'one long arg' another single
  2: ./go
#+end_src
However, using =env -S= solves this problem:
#+begin_src bash
  $ cat go
  #!/usr/bin/env -S /tmp/showargs single 'one long arg' another single
  $ ./go
  0: /tmp/showargs
  1: single
  2: one long arg
  3: another
  4: single
  5: ./go
#+end_src