Specifying a relative interpreter in a shebang
In order to make a Python script executable it needs to have a shebang line specifying the interpreter of the script.
This enables passing the script directly to
execve where the kernel can eventually call
/usr/bin/python3 with the script file as an argument. This works well but has the drawback of harcoding the interpreter. If a different interpreter is needed, like one located in a virtual environment, it cannot be used.
Instead of hardcoding an interpreter, the shebang line can use
env an argument cases
env to lookup that name in the
$PATH and execute that as the interpreter.
The user can then move their desired
python3 binary to the front of the
$PATH and that will be used to execute the script.
There are two limitations with using
env like above. First, it’s not possible to pass arguments to
env interprets the additional arguments as the name of the interpreter. For example trying to pass the
-E flag to
python3 results in the following error.
This is because
env does not split the arguments by spaces before passing them to
Second, this approach assumes the desired interpreter is on the front of the
$PATH. If it’s not possible to put the desired interpreter on the
$PATH then the correct interpreter will not be used.
It’s possible to overcome the above limitations by using the
-S flag to
env. The documentation explains that the
-S flag will split arguments on whitespace and pass them all to
execve. This means instead of just specifying a binary name, all of the values of
execve can be specified, such as specifying
-E to the interpreter.
This can be verified by passing
-v to get verbose output from
Selecting a relative interpreter
-S flag allows us to pass full arguments to an interpreter, it’s possible then to encode an entire program in the shebang line as an argument to another interpreter and have that execute our desired interpreter.
For example we could use
env -S to execute
/bin/sh and pass in a full script to
-c, where that script locates the desired interpreter relative to the script and then executes that. The documentation explains that spaces can be escaped with
env -S and
sh it’s possible to create a shebang line that executes an interpreter relative to the script. This could be used to have a script execute in a specific virtual environment.