Command line interfaces

Last updated on 2024-09-12 | Edit this page

Overview

Questions

  • What is a command-line interface (CLI)?
  • Why are they useful for making software easier to use for researchers?
  • How do I create a CLI for my research code?

Objectives

  • Learn what a command-line interface is
  • Understand the benefits of CLIs for making research code more accessible?
  • Gain a basic familiarity with the argparse module in Python

Command line interfaces


A command-line interface, usually abbreviated to CLI, is a terminal or prompt that accepts text input that instructs a computer what to do. They are used to start programs and perform actions within the computer’s operating system.

In this section, we’ll introduce the concept of providing a command-line interface to our research code to make it easier to use and provide a well-documented “entry point” to our software.

Advantages of CLIs for research tools

Command lines are a way of interacting with a digital system that go back to the early history of computing. They might seem old-fashioned because typing out commands means that there is no graphical component. It may seem restrictive because your mouse isn’t used, but terminals have a lot of power because we can formulate our instructions to the computer by writing commands. We have a direct line to control our computer’s operating system.

It’s a great way to “talk” to your computer because you can record the commands that you’ve run to provide a documented history of a research process. (We could record a video screen capture of your working procedure, but that’s much less efficient.)

Terminals are more efficient for running repetitive tasks and provide extra functionality for advanced users. They are an cost-effective way to provide a user interface for research software, as research teams often lack the resources and know-how to produce sophisticated graphical user interfaces.

Using the terminal


There’s a lot of powerful commands that can be learned to take full advantage of the command line, but here we’ll just address the basics to help us make our research software easier to use by providing a well-documented CLI.

This section will briefly introduce you to using the terminal to achieve simple tasks. For an an in-depth course on using the command line, please study the The Unix Shell Software Carpentry course.

How to open the command line

Each operating system has a slightly different terminal interface, but they work in basically the same way.

Example commands

An example of a CLI command is a simple text command that performs some action or interacts with the computer operating system.

Let’s examine a simple one-word command that lists the files in the current directory.

Arguments

Commands have options that allow the user to choose what the tool will do.

When using shell commands, we use the words option, flag, and arguments to describe parameters that we can use to modify the operation of that command and the inputs used to initialise our code.

Challenge

Try the command line statements described above.

  • How would you seek further help if you encounter an error?
  • What response does the terminal provide? Is this what you expect?

CLIs in R


This rest of this episode is focussed on the Python programming language.

R, while a powerful statistical computing language, doesn’t have a built-in module specifically designed for creating CLIs. Unlike Python, this means that you’ll need to use external packages or write your own functions to handle command-line arguments and options.

However, there are several packages that can help you create to CLIs in R:

These packages create CLIs for your R scripts, making them easier to distribute for others to use.

CLIs in Python


We can add a command-line interface to our Python code using the methods and tools that are included in the Python programming language.

Getting started

Let’s continue working on our birdsong identification software project and create an entry-point to our code.

To create an executable script that will run from the command line, create a file called oddsong/__main__.py. When a user runs our code from the terminal, this __main__.py file will be executed first.

This is a mechanism that tells Python how we want users to interact with our software.

To find out more, please read the __main__.py section in the Python documentation.

To run our code as a script we use the Python -m option that runs a module as a script.

BASH

python -m oddsong

This will execute the oddsong module by running our oddsong/__main__.py file.

Challenge

Let’s check if this works by writing a simple print() command in the __main__.py script.

PYTHON

# Show the text on the screen
print("Hello, world!")

Add this print statement to __main__.py. Run this script from the command line. What happens when you run python -m oddsong?

When you run the python -m oddsong command, Python runs the main module as a script.

You should see the following output in your terminal.

BASH

$ python -m oddsong
Hello, world!

main() functions

main functions are used to as the primary “starting point” for a command-line interface, otherwise known as an “entry point” for our scripted sequence of commands.

Inside this file, create a function called main() and an if statement as shown below.

PYTHON

def main():
    print("Identifying bird vocalisation...")

if __name__ == "__main__":
    main()

When the user executes our CLI, Python will know to run the main() function and execute our research code. In this case, our research code hasn’t been written yet, so we’ll just show a message on the screen for now.

The logical statement if __name__ == "__main__" means that the main() function will only run when the code is run from the comand line as the top-level code environment.

CLI documentation

Python has a useful inbuilt module called argparse to quickly create a command line interface that follows the standard conventions of the Linux software ecosystem.

To get started, attempt the challenge below.

Challenge

In this exercise, we’ll create an instance of the argument parser tool. Let’s edit our Python script.

First, load the argparse library using the import keyword, which is conventionally done at the top of the script. Then, we’ll add the argument parser to our main() function so it loads when the script runs.

PYTHON

import argparse

def main():
    # Define command-line interface
    parser = argparse.ArgumentParser()
    parser.parse_args()

    print("Identifying bird vocalisation...")

if __name__ == "__main__":
    main()

This creates a basic command line interface. Let’s try it out.

BASH

python -m oddsong

What do expect to see? What actually happens?

Now let’s ask for help! Run the following command to view the usage instructions:

BASH

python -m oddsong --help

What should we see when using the --help flag? What happens in your temrinal?

When we run our script as before, it will run like normal with no change in behaviour.

BASH

$ python -m oddsong
Identifying bird vocalisation...

But, if we invoke the command-line interface using any arguments, then this new functionality kicks in.

BASH

$ python -m oddsong --help
usage: test.py [-h]

options:
  -h, --help  show this help message and exit

This is the default output of a CLI with no additional arguments specified. The first line displays the usage instructions. This means that we may execute test.py with an optional help option using --help or -h for short. Optional flags are denoted with square brackets like this [-h].

The parse_args() method runs the parser and makes our arguments available to the user on the command line. This makes the default --help flag available which displays instructions and notes that we can customise. As we continue to develop our CLI by adding arguments, each one will be listed and described in this help page. This is an excellent way to document our software and make it available to researchers!

Arguments

But what if we want to take an input from the user? We add arguments to our CLI using the following syntax.

PYTHON

# Add the category argument
parser.add_argument('-c', '--category')

This will create an argument called args.file that the user can specify when they run our script, and that we can use in our code to do something useful.

Challenge

Add this argument to our script and note the changes to the user interface.

The code now looks something like that shown below.

PYTHON

import argparse

def main():
    # Define command-line interface
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--category')
    parser.parse_args()

    print("Identifying bird vocalisation...")

if __name__ == "__main__":
    main()

Note that we add the argument before we parse them, which makes them available to use.

Now, when we invoke the help screen, we see our new “category” argument listed.

BASH

$ python -m oddsong --help
usage: oddsong.py [-h] [-c CATEGORY]

options:
  -h, --help            show this help message and exit
  -c CATEGORY, --category CATEGORY

The layout of this text is done for us and follows the standard conventions of terminal tools.

Of course, if you’ve imbibed the spirit of the course, you’ll notice that our new category parameter is completely undocumented! It’s unclear what it is or how to use this option.

Argument descriptions

To provide a concise explanation for each parameter we use the help argument of the add_argument() function as shown below.

PYTHON

# Add the category argument
parser.add_argument('-c', '--category', 
    help="The type of bird call e.g. alarm, contact, flight")

This text should briefly describe the purpose of the argument, without going into too much detail (which should be covered in the user guide.)

Challenge

Add a description of the --category argument using the add_argument() function. What change do you expect to happen in your CLI?

We can achieve this in our example script by adding a help string.

PYTHON

import argparse

def main():
    # Define command-line interface
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--category',
        help="The type of bird call e.g. alarm, contact, flight")
    parser.parse_args()

    print("Identifying bird vocalisation...")

if __name__ == "__main__":
    main()

Now, when we call the --help option, we see this description as an annotation to that argument.

BASH

$ python -m oddsong --help
usage: oddsong.py [-h] [-c CATEGORY]

options:
  -h, --help            show this help message and exit
  -c CATEGORY, --category CATEGORY
                        The type of bird call e.g. alarm, contact, flight

There’s a lot more to learn about command line arguments, including several powerful features of the argparse library, but these are beyond the scope of this course.

Description

We can provide a simple summary of the software that will be displayed on the --help screen of our CLI by using the description argument when creating our argument parser object. This should concisely inform the user about the purpose of the tool and how it works.

PYTHON

# Describe the software
parser = argparse.ArgumentParser(
    description="A tool to identify bird vocalisations.")

Challenge

Write your own description for our software. Where does it display on our help screen?

We define the description when creating our argument parser object.

PYTHON

import argparse

def main():
    # Define command-line interface
    parser = argparse.ArgumentParser(
        description="A tool to identify bird vocalisations.")
    parser.add_argument('-c', '--category',
        help="The type of bird call e.g. alarm, contact, flight")
    parser.parse_args()

    print("Identifying bird vocalisation...")

if __name__ == "__main__":
    main()

This text is displayed after the usage instruction.

BASH

$ python -m oddsong --help
usage: oddsong.py [-h] [-c CATEGORY]

A tool to identify bird vocalisations.

options:
  -h, --help            show this help message and exit
  -c CATEGORY, --category CATEGORY
                        The type of bird call e.g. alarm, contact, flight

Usage

By default, the usage message is generated automatically based on the arguments of our script. For our example, the usage instructions look like this:

usage: oddsong.py [-h] [-c CATEGORY]

In most cases, this will do the job. If you want to overwrite this message then use the usage parameter when creating the argument parser object.

There are several other options to customise your CLI, but we’ve covered here the primary ways to document your research software to make it easier to use by your collaborators and other researchers.

Key Points

  • Command line interfaces (CLIs) are terminal commands that provide an easy-to-use entry point to a software package.
  • Researchers can use CLIs to make their research code easier to use by providing well-documented options, hiding the complexity of the software.
  • Most programming languages offer frameworks for creating CLIs. In Python, we do this using the argparse library.

Further resources


To find out more about command-line interfaces and using the terminal to improve your productivity for research computing, please refer to the following resources:

  • Learn more about using the terminal in the Software Carpentry Unix Shell course.
  • There are Python packages such as Click that provide a framework for building bigger, more complex command-line interfaces.
  • To learn about distributing your CLI so others can easily install and use it, please see the packaging module in this course series.