The shebang line is interpreted by the kernel and is not very flexible. On Linux, it's limited to a single argument: the syntax is #!
, optional whitespace, path to the interpreter (not containing whitespace), optional whitespace, and optionally a single argument (which may contain whitespace except at the beginning). Furthermore the total size of the shebang line is limited to 128 bytes (BINPRM_BUF_SIZE
constant in the kernel sources, used in load_script
).
If you want to pass more than one argument, you need a workaround. If you're using #!/usr/bin/env
for path expansion, then there's only room for the command name and no other argument.
The most obvious workaround is a wrapper script. Instead of having /path/to/my-script
contain the mocha code, you put the mocha code in some other file /path/to/my-script.real
and make /path/to/my-script
a small shell script. Here's a sample wrapper that assumes that the real code is in a file with the same name as the script, plus .real
at the end.
#!/bin/sh
exec mocha --reporter=tap --output=foo "$0.real" "$@"
With a shell wrapper, you can take the opportunity to do more complex things such as define environment variables, look for available interpreter versions, etc.
Using exec
before the interpreter ensures that the mocha script will run in the same process as the shell wrapper. Without exec
, depending on the shell, it might run as a subprocess, which matters e.g. if you want to send signals to the script.
Sometimes the wrapper script and the actual code can be in the same file, if you manage to write a polyglot — a file that is valid code in two different languages. Writing polyglots is not always easy (or even possible) but it has the advantage of not having to manage and deploy two separate files. Here's a JavaScript/shell polyglot where the shell part executes the JS interpreter on the file (assuming that the JS interpreter ignores the shebang line, there isn't much you can do if it doesn't):
#!/bin/sh
///bin/true; exec mocha --reporter=tap --output=foo "$0" "$@"
… (the rest is the JS code) …
#!
and!#
, so you can have as complicated a shell / Perl / Python / Ruby script in there as you like to find and start a suitable JVM, locate the Scala installation, figure out appropriate arguments and configuration options for the JVM and the Scala compiler and so on, then justexec
whatever command line you cobbled together, and Scala will ignore the script portion. – Jörg W Mittag Mar 25 '17 at 11:59