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.
This will execute the oddsong
module by running our
oddsong/__main__.py
file.
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.
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.
What do expect to see? What actually happens?
Now let’s ask for help! Run the following command to view the usage instructions:
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.
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.
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.
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.
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.