Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Making command-line programs in Python

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.

Concepts

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

Interface

Standard input (stdin)
usually the output from a pipe
Standard output (stdout)
usually text printed to the screen

Piping

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 2.

A simple Python CLI program

(CLI is command-line interface.)

This program, shout.py, takes standard input, uppercases it, and prints it to standard output. So given hello world it returns HELLO WORLD!.

import sys
stdin = sys.stdin.read()
print(stdin.upper())

Run it with:

echo "hello world" | python shout.py

And it should return HELLO WORLD.

Using arguments

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 file1, file2, 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 argv.py:

print(sys.argv)

Then run it with:

python argv.py arg1 arg2 arg3

And you should see ['argv.py', 'arg1', 'arg2', 'arg3'].

Using 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

Prints:

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment