Making command-line programs in Python
From a workshop given at the Python User Group, Foundations for Research Computing, Columbia University, on November 3rd, 2020.
The UNIX Philosophy
- A program should do one thing, and do it well.
- Programs should be interoperable by reading and writing text over standard input and standard output
- Standard input (stdin)
- usually the output from a pipe
- Standard output (stdout)
- usually text printed to the screen
echo "Hello world!"
This program prints “Hello world!” to the screen (to standard output). That output can be piped
| into another program.
echo "Hello world!" | wc -w
Here, the standard output from
echo "Hello world!"~ is being piped into ~wc (word count), which accepts standard input, and returns its word count. It should return
A simple Python CLI program
(CLI is command-line interface.)
shout.py, takes standard input, uppercases it, and prints it to standard output. So given
hello world it returns
import sys stdin = sys.stdin.read() print(stdin.upper())
Run it with:
echo "hello world" | python shout.py
And it should return
Arguments are what come after the program name when you’re calling a program on the command line. So in the command
cat file1 file2 file3,
cat is the name of the command, and
file3 are arguments. Here, they correspond to files, and that command prints out the contents of all of those files, concatenated together.
Try this in a file called
Then run it with:
python argv.py arg1 arg2 arg3
And you should see
['argv.py', 'arg1', 'arg2', 'arg3'].
sys.argv, let’s make a weird version of
cat that prints out the contents of files whose filenames are given as arguments, only uppercased.
import sys for filename in sys.argv: contents = open(filename).read() print(contents.upper())
Using argparse for handling options
Let’s say we wanted to write a command-line program that, like
wc, gave the user options for how to shout its input. If you run
python shout.py it should shout whatever it’s given (i.e. uppercase it). And if you run
python shout.py --loud, it should add a bunch of exclamation points to the end, making it extra loud.
import sys import argparse stdin = sys.stdin.read() # description will appear as our program's help. parser = argparse.ArgumentParser(description='Shout it out!') # action='store_true' says: if this option is present, assign args.loud to True. # Otherwise assign it to False (the default.) parser.add_argument('--loud', action='store_true', help='whether to add exclamation points') args = parser.parse_args() output = stdin.upper() if args.loud: output += '!!!' print(output)
echo "hello" | python shout.py # HELLO
echo "hello" | python shout.py --loud # HELLO!!!
Our program now also has automatically-generated documentation (help) for the user:
echo "hello" | python shout.py --help
usage: shout.py [-h] [--loud] Shout it out! optional arguments: -h, --help show this help message and exit --loud whether to add exclamation points
For more uses of
argparse, see the library’s documentation.