Complete guide to writing command-line tools

A command-line application is an application that you can run from your terminal (e.g. from bash).

In this guide we will review what makes a good command-line application and see how to implement one easily using python 3.

The first chapter focuses on inputs, and in particular, how to get inputs through the command-line interface.

Chapter 1: The command-line interface

  1. What is a command-line interface?
  2. The argument vector
  3. How to write a CLI in python? (using click)
  4. Good practices and conventions
  5. Design a great help text
  6. Enable auto-completion
  7. How to structure your code?

The second chapter focuses on ouputs. There are two standard streams and it is important to choose the right one for proper interoperability with the script's environment.

Chapter 2: How and when to use stdout and stderr

  1. stdout, stderr and unix pipelines
  2. Use standard error through the logging module
  3. Only use print for the script's main output
  4. Improve terminal experience
  5. Securely prompt for passwords
  6. Colors, the cross-platform way
  7. Progress bars that work

In chapter 3, we turn to another form of input/output: the signals.

Chapter 3: Catch and handle signals

  1. Interrupt a process with ctrl+c
  2. Pause and resume a process with ctrl+z and fg
  3. Handle signals using the signal module

The last and upcoming chapter will tackle the packaging and redistribution of your application.

Additional tips

Here are additional tips that didn't fit into the previous articles and that aren't big enough to make it into their own.

Use stdin instead of open(file)

If the goal of your script is to transform a bunch of text lines (like grep and wc do), you should read those lines from stdin instead of forcing the user to use a real file.

Why? Because that way your script can be used in combination with others through pipes. When someone wants to use your script with a file on disk, cat can be used to pipe the file into the script's stdin. Here's an example:

cat file.txt | grep "scripting.tips" | myscript

In the command above, the file file.txt is filtered by grep to keep only the lines that contain "scripting.tips" and then the result is sent to myscript.

Choose your exit codes

Each process can terminate with an exit code. The convention is that 0 means success, while non-zero exit codes mean that an error occured. According to sys.exit documentation, the unix convention is to use 2 for a command-line syntax error and 1 for any other error. Here's how to use it:

import sys

# ...

if error:
    sys.exit(1)