An Introduction to the Command-Line (on Unix-like systems)
by Oliver; 201420. File Suffixes
As we begin to script it's worth following some file naming conventions. We should use common sense suffixes, like:- .txt - for text files
- .html - for html files
- .sh - for shell scripts
- .pl - for Perl scripts
- .py - for Python scripts
- .cpp - for c++ code
$ ls *.txtList all text files in the cwd and below (i.e., including child directories):
$ find . -name "*.txt"
[1] An astute reader noted that, for commands—as opposed to, say, html or text files—using suffixes is not the best practice because it violates the principle of encapsulation. The argument is that a user is neither supposed to know nor care about a program's internal implementation details, which the suffix advertises. You can imagine a program that starts out as a shell script called mycommand.sh, is upgraded to Python as mycommand.py, and then is rewritten in C for speed, becoming the binary mycommand. What if other programs depend on mycommand? Then each time mycommand's suffix changes they have to be rewritten—an annoyance. Although I make this sloppy mistake in this article, that doesn't excuse you! Read the full argument
Update: There's a subtlety inherent in this argument that I didn't appreciate the first time around. I'm going to jump ahead of the narrative here, so you may want to skip this for now and revist it later. Suppose you have two identical Python scripts. One is called hello.py and one is simply called hi. Both contain the following code:
#!/usr/bin/env python def yo(): print('hello')In the Python shell, this works:
>>> import hellobut this doesn't:
>>> import hi Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named hiBeing able to import scripts in Python is important for all kinds of things, such as making modules, but you can only import something with a .py extension. So how do you get around this if you're not supposed to use file extensions? The sage answers this question as follows:
The best way to handle this revolves around the core question of whether the file should be a command or a library. Libraries have to have the extension, and commands should not, so making a tiny command wrapper that handles parsing options and then calls the API from the other, imported one is correct.To elaborate, this considers a command to be something in your PATH, while a library—which could be a runnable script—is not. So, in this example, hello.py would stay the same, as a library not in your PATH:
#!/usr/bin/env python def yo(): print('hello')hi, a command in your PATH, would look like this:
#!/usr/bin/env python import hello hello.yo()Hat tip: Alex
↑