2

In the pip program, the She-bang is

#!/usr/local/bin/python

if __name__ == "__main__":
    # Python program body

while in the Install Certificates.command that Python Launcher offers:

#!/bin/sh

/Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6 << "EOF"

# python program body

EOF

Are there any differences between those two approaches? And is there any reason to prefer one to another?

It seems to me they are all the same, except for the second one has one more bash subroutine. Is this right?

3
  • 1
    As an aside, #!/user/bash is probably not useful on any mainstream platform. It could be the home directory of a user whose account name is bash on a MacOS system. I'm guessing you are probably actually looking at #!/usr/bin/bash (and the other typos reinforce this impression). Commented Feb 3, 2019 at 9:46
  • There is no bash "subroutine" here. The second script is just a shell script which runs Python. Commented Feb 3, 2019 at 9:53
  • @tripleee Yes, that is a typo, and I've corrected it. Thanks. Commented Feb 3, 2019 at 11:48

3 Answers 3

3

In the general case, you simply want to specify the interpreter you actually want.

Outside of this, you sometimes see workarounds like this as portability hacks. On POSIX systems, /usr/bin/env covers the majority of scenarios quite nicely; but if you need portability to older or otherwise peculiar systems, falling back to the lowest common denominator and then working your way back up to a place where you can reliably run e.g. Python on a variety of systems may require all kinds of unobvious constructs. (The previous - upvoted! - answer by Dan D. is a good example.)

There are also cases where you want sh to set something up (fetch some environment variables which are specified in a file which uses sh syntax, for example) and then hand over execution to Python;

#!/bin/sh
# source some variables
. /etc/defaults/myenv.sh
# Then run Python
exec env python -c '
# ... Your Python script here
    ' "$@"
Sign up to request clarification or add additional context in comments.

1 Comment

Another common example is the Perl "preamble".
2

There is a line length limit on the #! line. Perhaps they did that to get around that.

The options are the path to the program but only if it is short enough. Use of env python which uses the path. Or chain loading like this.

6 Comments

Are you sure? I just tested it and found the line limit on shebang on Mac OS X is 511 characters. Usually it is 127 characters. But they were nowhere near either of those limits.
@AlexHarvey I can't be. We don't know how long the ellipsis in the path is. But perhaps the author of that file thought the limit was much lower and didn't bother testing before using the workaround.
Or the real path to Python could be even longer on some systems they need to support. A "one size fits all" solution is going to be easier to debug, maintain, and document.
There are multiple versions of pip on my MBP, and the longer one I can find is #!/Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6 Which is already quite long. But it's only 65 characters. Even if the line limit is 127, it's still quite hard to hit double the length of this path. And this is set by default when installing pip with python 3.6. So I don't know if this would be the reason for this.
@tripleee, fyi the source code refs are here and here. This code only seems to exist for making Mac OS X DMG packages. I guess as suggested, the author just didn't know what the shebang line limit was? Puzzling code!
|
2

This specific code for the Install Certificates.command script was introduced in Python Issue #17128. As far as I can tell, the author hasn't explained why he wrote the code this way.

Note that .command files are Shell scripts on Mac OS X that can be executed by double-clicking on them in Finder.

I believe the likely explanation is that the author simply wanted to honour Mac OS X's expectation that .command files should be Shell scripts.

You could test this by placing the following content in a file ~/Desktop/test.command:

#!/usr/bin/env python
print "Hello world"

Then view the Desktop folder in Finder, and note that it is reported as a "shell" file:

enter image description here

(Although it is reported incorrectly as a Shell file, this Python script can still be executed by double-clicking on it. It doesn't break Finder or anything.)

To answer the specific question, one reason for preferring this pattern might be, as Dan D. said, to avoid a Shebang line limit.

In general, you would prefer to use #!/usr/bin/env python as your Shebang line. Creating a Bash Heredoc (i.e. the python3.6 << EOF pattern) would create all sorts of problems, such as your syntax highlighting won't work, you have to watch out for Bash variable interpolation inside the Heredoc, etc.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.