Welcome, guest | Sign In | My Account | Store | Cart

This dual-mode script is both a Posix shell script and a python script. The shell part looks like a triple-quoted string to the Python interpreter. The shell does not reach anything after the exec statement.

Python, 10 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/usr/bin/env python -E

print "Nope, this doesn't work"



#!/bin/sh
LOADER=''''; exec python -E "$0" "$@" #'''

print "This Python script is also a shell script!"

In this example, the -E argument is passed to the interpreter in order to prevent environment variables like PYTHONPATH from affecting the script. If you try to add this option on the standard #! header line this will not work - it will search for an executable named "python -E" and fail.

This trick can also have other uses. For example, it can search for an appropriate python version to run in different environments where "python" can be either python2 or python3. The triple-quoted string may be safely extended to a multiline script.

2 comments

Justin 12 years, 7 months ago  # | flag

I think you are mistaken. This is simply a Python script. The "#!/bin/sh" is a Python comment and is therefore skipped during runtime. LOADER=''' .* ''' is simply a triple quoted Python string. This executes one process and SH has nothing to do with it.

Oren Tirosh (author) 12 years, 7 months ago  # | flag

Yes, from the point of view the a Python interpreter this is simply a python script with a comment and a triple quoted string.

From the point of view of the kernel of a unix-like operating system this is a script with a hashbang header - if you set the execute permissions on this file and pass it to an exec* system call the kernel will detect that the first two bytes in the file are '#' and '!' and interpret the rest of the first line as an executable to run (in this case /bin/sh), passing the name of the script as the first argument, with any other arguments passed to the exec call appended.

From the point of view of the shell, this is a shell script starting with a comment line, an assignment of two concatenated empty strings to a variable named LOADER, followed by an exec statement. The second line ends with a shell comment. The shell doesn't get to see the rest of the file because the exec statement never returns (and unlike python, the shell does not try to parse the entire file first).

And just in case this wasn't obvious - these are two separate scripts. The first one is and example of what doesn't work: the env command, used to search for python in the search path gets the arguments ("python -E", "/path/to/script") rather than ("python", "-E", "/path/to/script").

Created by Oren Tirosh on Sun, 21 Aug 2011 (MIT)
Python recipes (4591)
Oren Tirosh's recipes (16)

Required Modules

  • (none specified)

Other Information and Tasks