CLI#

In this class we’ve been writing CLI programs, as opposed to a GUI. While most of the programs an average person interacts with on a day-to-day basis are most likely GUIs, text-based programs have their advantages.

They can often be faster, as they take up fewer resources needing to load and render graphics. The interface can be more precise and less error prone to interact with, as typed commands are less ambiguous than clicking on regions. And they can be powerful, making it possible to accomplish a lot by stringing together just a few commands. Plus, they’re a lot easier to write.

In this lesson we’ll learn about writing programs intended to be run in a command line environment.

Table of Contents

Part 1: Arguments#

Just like functions can take arguments, so can programs. This is done on the command line, typically separated by spaces, with multi-word arguments surrounded by single or double quotes.

In Python, those arguments can be accessed at sys.argv which stores a list of strings. The first list item is the name of the program being executed followed by one argument per list item.

Note all arguments are stored as strings, so as in the following example, type conversion is often necessary.

Listing 260 example: program.py#
1import sys
2print(sys.argv)
Listing 261 command line#
$ python program.py arg1 arg2 arg3
['cli.py', 'arg1', 'arg2', 'arg3']

$ python program.py "multi-word argument 1" arg2
['cli.py', 'multi-word argument 1', 'arg2']

This can be used to control program behavior, in major or minor ways. Here for example is a simple program randnums.py which prints 3 random numbers by default, or the number specified by the first argument if one exists.

Listing 262 example: randnums.py#
 1import sys
 2import random
 3
 4count = 3
 5
 6if len(sys.argv) >= 2:
 7  count = int(sys.argv[1])
 8
 9for _ in range(count):
10  print(random.randint(0, 100))
Listing 263 command line#
$ python randnums.py
50
62
76

$ python randnums.py 2
15
46

Part 1.1: Exercise#

Exercise 80 (Countdown With Args Exercise)

Write a program which counts down from 3 by default, or from the number passed by the first argument if present. Use time.sleep() to pause for a second between printing each number.

Example output:

$ python countdown.py
3...
2...
1...

$ python countdown.py 5
5...
4...
3...
2...
1...

Part 2: Environment Variables#

Just like we can set variables in our programs, we can also set variables on the command line. There are known as environment variables, and they are typically stored as all caps. For example, most systems set the variables SHELL, TERM, HOME and TMPDIR.

To reference a variable on the command line, prefix it with a $.

Listing 265 command line#
$ echo $SHELL
/bin/zsh

$ echo $TERM
xterm-256color

$ echo $HOME
/Users/pythonclass

$ echo $TMPDIR
/var/folders/mn/qt2cdhdn5md6hrwjrz5sp60m0000gn/T/

To set an environment variable, use the typeset or export command as in the following example. (Note: The variable only exists only for the duration of your current terminal session.)

Listing 266 command line#
$ typeset -gx LANGUAGE=en
$ export LANGUAGE=en

In Python, we can access this using the os.environ dictionary.

import os
print(os.environ["TERM"])
xterm-color

If you’re not sure if the environment variable exists, use the .get() method, with an optional second argument that will be the value returned if it is missing.

import os
lang = os.environ.get("LANGUAGE", "en")
print(lang)
en

Part 2.1: Exercise#

Exercise 81 (Environment Variables Exercise)

Modify your countdown program to check the environment variable VERBOSE and the message "Counting down from COUNT." if it is set to a non-blank value.

Test it with the envionment variable not set, set to "", and set to a value like "yes".

Part 3: Input and Output#

In a command line environment, input and output are handled via three special kinds of files called that serve as data streams: stdin, stdout and stderr. Each one has an associated FD number, which we’ll learn more about later.

Descriptor

Name

FD

Source / Destination

stdin

standard input

0

from the keyboard

stdout

standard output

1

to the screen

stderr

standard error

2

to the screen

In Python, these can be accessed in the sys module.

When you use the print() function, for example it prints to stdout by default. This is the same as:

import sys
print("hello", file=sys.stdout)
hello

As I mentioned, these are all special kinds of files, and in Python they are represented as file handler objects. As such, you can interact with them the same way you would with a normal file object. So yet another way to accomplish the same thing is:

import sys
sys.stdout.write("hello\n")
hello
6

The most common use of file handlers is to write to stderr instead of stdout.

import sys
print("Danger, Will Robinson!", file=sys.stderr)
Danger, Will Robinson!

This is useful because on those streams can be handled separately on the command line. While a complete lesson on redirection is outside of the scope of this lesson, the most common use case is to send a particular stream to a different destination with the syntax: COMMAND FD> DESTINATION.

The following for example sends the results of the ls command to the file files.txt. (The file descriptor defaults to stdout.)

Listing 269 command ine#
$ ls > files.txt

Or we could send all error messages to errors.log or to /dev/null (on most systems) to silence them completely. Here we use the file descriptor number 2 immediately before the > to indicate that we want to redirect stderr instead of stdout.

Listing 270 command ine#
$ ls 2> errors.log
file1 file2 file3

$ ls 2> /dev/null
file1 file2 file3

Take the following example, which prints some messages to stderr and others to stdout.

Listing 271 using-stderr.py#
1import sys
2print("Welcome!")
3print("Danger, Will Robinson!", file=sys.stderr)
4print("Farewell.")

If we redirect stdout to the file messages.txt the faux error message will be printed to the screen and excluded from the messages.txt file.

Listing 272 command ine#
$ python using-stderr.py > messages.txt
Danger, Will Robinson!

$ cat messages.txt
Welcome!
Farewell.

Part 3.1: Exercise#

Exercise 82 (Stderr Exercise)

Modify your countdown function to print a message to stderr if there is more than one argument passed.

Test this on the command line with more than one argument by:

  • redirecting stdout to countdown.txt

  • redirecting stderr to errors.log

  • redirecting stderr to /dev/null

Part 4: Exiting Programs#

When a command line programs ends, it returns an exit code to indicate success or failure. Traditionally an exit code of 0 indicates success and anything else indicates some kind of failure. Some programs use different exit codes to let you know why the program failed.

You can see the exit code of the last command with the special variable $?. Lets use the ls command as an example.

Listing 275 command line#
$ ls
file1 file2 file3

$ echo $?
0

$ ls x
ls: cannot access 'x': No such file or directory

$ echo $?
2

To exit a program in Python use sys.exit() with an optional exit code argument. In the following example we expand the randnums.py script to exit with an exit code of 1.

Listing 276 example: randnums.py#
 1import sys
 2import random
 3
 4count = 3
 5
 6if len(sys.argv) > 2:
 7  print(f"Warning: extra arguments: {sys.argv[2:]}", file=sys.stderr)
 8
 9if len(sys.argv) >= 2:
10
11  if not sys.argv[1].isnumeric():
12    print("Count must be a number.")
13    sys.exit(1)
14
15  count = int(sys.argv[1])
16
17for _ in range(count):
18  print(random.randint(0, 100))

Part 4.1: Exercise#

Exercise 83 (Exiting Exercise)

Modify your countdown program, so that when an argument is passed that is not a number, print an error message and exit with an exit code of 1. Test with both numeric and non-numeric arguments.

Part 5: Terminal size#

If you need to know the size of the terminal, you can use the shutil.get_terminal_size() function.

import shutil
shutil.get_terminal_size()
os.terminal_size(columns=80, lines=24)

It returns a terminal_size object, which provides the properties columns and lines.

import shutil

size = shutil.get_terminal_size()
print("width:", size.columns)
print("height:", size.lines)
width: 80
height: 24

It is also a special kind of tuple, which means you can make use of multiple assignment.

import shutil

width, height = shutil.get_terminal_size()
print("width:", width)
print("height:", height)
width: 80
height: 24

On systems where the size cannot be determined, the defaults (80, 24) will be used. To change the defaults, send an tuple argument with (columns, lines).

import shutil
width, height = shutil.get_terminal_size((125, 33))
print("width:", width)
print("height:", height)
width: 125
height: 33

Part 5.1: Exercise#

Exercise 84 (Terminal Size Exercise)

In the following example, we use the width from get_terminal_size() print the text "Hello world!" centered on the screen.

Part 6: Colors and Styles#

Many terminals use ANSI escape codes to control the font colors and style and many other things.

Fortunately, there are modules that handle all the complication of escape codes for us. The one I recommend is console, which works on Mac/Linux/Windows.

Important

Not all systems support escape codes, though one advantage to using a module like this is that it does its best to detect if colors will work with that system, and if not, does nothing.

Just be careful not to rely too heavily on colors and styles, so your program still works even if they don’t show up. Also, be aware that some colors look different or are harder to read with a different background color, so its a good idea to test with a light and back background color.

Part 6.1: Installation#

Listing 280 command line#
pip install console

Part 6.2: Usage#

To see a demo of all available features and how they work in your terminal you can run console.demo from the command line.

Listing 282 command line#
python -m console.demos

To change the text colors and styles, use the fg, bg and fx objects to change the foreground color, background color, and effects respectively.

from console import fg, bg, fx

For text effects, use the methods on the fx object.

print(fx.bold("Attention!"))

For foreground and background colors use methods on the fg and bg objects respectively, such as the 16 basic colors supported by most terminals.

print(fg.green("SUCCESS"))
print(bg.magenta("Information"))

Some terminals also provide an extended set of 256 indexed colors (shown in the aforementioned demo). Methods for these colors are named i0 through i255.

print(fg.i197("Error"))

For terminals that support “True”, RGB, or 16 million colors, you can use any 6-character hex color code prefixed with t_.

print("default=" + fg.t_f4c2c2("None"))

Or you can use X11 color names, prefixed with x_.

print(bg.midnightblue("Home"))
print(fg.x_deepskyblue("Tutorial"))

You can combine a fg, bg, and/or fx object to create a custom, callable style.

highlight = fx.italic + fg.yellow + bg.blue
print(highlight("Great job!"))

Part 6.3: Available colors and styles#

Text Effects

Text effects methods available via the fx object:

Basic Colors

Methods for the 16 basic colors available via the fg and bg objects.

X11 Colors

Methods for RGB colors associated with X11 color names available via the fg and bg objects.

  • b

  • blink

  • bold

  • conceal

  • crossed

  • curly_underline

  • dim

  • double_underline

  • dunder

  • encircle

  • fastblink

  • frame

  • hide

  • i

  • italic

  • overline

  • reverse

  • s

  • slowblink

  • strike

  • u

  • underline

  • black

  • blue

  • cyan

  • green

  • lightblack

  • lightblue

  • lightcyan

  • lightgreen

  • lightmagenta

  • lightpurple

  • lightred

  • lightwhite

  • lightyellow

  • magenta

  • purple

  • red

  • white

  • yellow

  • snow

  • ghostwhite

  • whitesmoke

  • gainsboro

  • floralwhite

  • oldlace

  • linen

  • antiquewhite

  • papayawhip

  • blanchedalmond

  • bisque

  • peachpuff

  • navajowhite

  • moccasin

  • cornsilk

  • ivory

  • lemonchiffon

  • seashell

  • honeydew

  • mintcream

  • azure

  • aliceblue

  • lavender

  • lavenderblush

  • mistyrose

  • white

  • black

  • darkslategray

  • darkslategrey

  • dimgray

  • dimgrey

  • slategray

  • slategrey

  • lightslategray

  • lightslategrey

  • gray

  • grey

  • lightgrey

  • lightgray

  • midnightblue

  • navy

  • navyblue

  • cornflowerblue

  • darkslateblue

  • slateblue

  • mediumslateblue

  • lightslateblue

  • mediumblue

  • royalblue

  • blue

  • dodgerblue

  • deepskyblue

  • skyblue

  • lightskyblue

  • steelblue

  • lightsteelblue

  • lightblue

  • powderblue

  • paleturquoise

  • darkturquoise

  • mediumturquoise

  • turquoise

  • cyan

  • lightcyan

  • cadetblue

  • mediumaquamarine

  • aquamarine

  • darkgreen

  • darkolivegreen

  • darkseagreen

  • seagreen

  • mediumseagreen

  • lightseagreen

  • palegreen

  • springgreen

  • lawngreen

  • green

  • chartreuse

  • mediumspringgreen

  • greenyellow

  • limegreen

  • yellowgreen

  • forestgreen

  • olivedrab

  • darkkhaki

  • khaki

  • palegoldenrod

  • lightgoldenrodyellow

  • lightyellow

  • yellow

  • gold

  • lightgoldenrod

  • goldenrod

  • darkgoldenrod

  • rosybrown

  • indianred

  • saddlebrown

  • sienna

  • peru

  • burlywood

  • beige

  • wheat

  • sandybrown

  • tan

  • chocolate

  • firebrick

  • brown

  • darksalmon

  • salmon

  • lightsalmon

  • orange

  • darkorange

  • coral

  • lightcoral

  • tomato

  • orangered

  • red

  • hotpink

  • deeppink

  • pink

  • lightpink

  • palevioletred

  • maroon

  • mediumvioletred

  • violetred

  • magenta

  • violet

  • plum

  • orchid

  • mediumorchid

  • darkorchid

  • darkviolet

  • blueviolet

  • purple

  • mediumpurple

  • thistle

  • snow1

  • snow2

  • snow3

  • snow4

  • seashell1

  • seashell2

  • seashell3

  • seashell4

  • antiquewhite1

  • antiquewhite2

  • antiquewhite3

  • antiquewhite4

  • bisque1

  • bisque2

  • bisque3

  • bisque4

  • peachpuff1

  • peachpuff2

  • peachpuff3

  • peachpuff4

  • navajowhite1

  • navajowhite2

  • navajowhite3

  • navajowhite4

  • lemonchiffon1

  • lemonchiffon2

  • lemonchiffon3

  • lemonchiffon4

  • cornsilk1

  • cornsilk2

  • cornsilk3

  • cornsilk4

  • ivory1

  • ivory2

  • ivory3

  • ivory4

  • honeydew1

  • honeydew2

  • honeydew3

  • honeydew4

  • lavenderblush1

  • lavenderblush2

  • lavenderblush3

  • lavenderblush4

  • mistyrose1

  • mistyrose2

  • mistyrose3

  • mistyrose4

  • azure1

  • azure2

  • azure3

  • azure4

  • slateblue1

  • slateblue2

  • slateblue3

  • slateblue4

  • royalblue1

  • royalblue2

  • royalblue3

  • royalblue4

  • blue1

  • blue2

  • blue3

  • blue4

  • dodgerblue1

  • dodgerblue2

  • dodgerblue3

  • dodgerblue4

  • steelblue1

  • steelblue2

  • steelblue3

  • steelblue4

  • deepskyblue1

  • deepskyblue2

  • deepskyblue3

  • deepskyblue4

  • skyblue1

  • skyblue2

  • skyblue3

  • skyblue4

  • lightskyblue1

  • lightskyblue2

  • lightskyblue3

  • lightskyblue4

  • slategray1

  • slategray2

  • slategray3

  • slategray4

  • lightsteelblue1

  • lightsteelblue2

  • lightsteelblue3

  • lightsteelblue4

  • lightblue1

  • lightblue2

  • lightblue3

  • lightblue4

  • lightcyan1

  • lightcyan2

  • lightcyan3

  • lightcyan4

  • paleturquoise1

  • paleturquoise2

  • paleturquoise3

  • paleturquoise4

  • cadetblue1

  • cadetblue2

  • cadetblue3

  • cadetblue4

  • turquoise1

  • turquoise2

  • turquoise3

  • turquoise4

  • cyan1

  • cyan2

  • cyan3

  • cyan4

  • darkslategray1

  • darkslategray2

  • darkslategray3

  • darkslategray4

  • aquamarine1

  • aquamarine2

  • aquamarine3

  • aquamarine4

  • darkseagreen1

  • darkseagreen2

  • darkseagreen3

  • darkseagreen4

  • seagreen1

  • seagreen2

  • seagreen3

  • seagreen4

  • palegreen1

  • palegreen2

  • palegreen3

  • palegreen4

  • springgreen1

  • springgreen2

  • springgreen3

  • springgreen4

  • green1

  • green2

  • green3

  • green4

  • chartreuse1

  • chartreuse2

  • chartreuse3

  • chartreuse4

  • olivedrab1

  • olivedrab2

  • olivedrab3

  • olivedrab4

  • darkolivegreen1

  • darkolivegreen2

  • darkolivegreen3

  • darkolivegreen4

  • khaki1

  • khaki2

  • khaki3

  • khaki4

  • lightgoldenrod1

  • lightgoldenrod2

  • lightgoldenrod3

  • lightgoldenrod4

  • lightyellow1

  • lightyellow2

  • lightyellow3

  • lightyellow4

  • yellow1

  • yellow2

  • yellow3

  • yellow4

  • gold1

  • gold2

  • gold3

  • gold4

  • goldenrod1

  • goldenrod2

  • goldenrod3

  • goldenrod4

  • darkgoldenrod1

  • darkgoldenrod2

  • darkgoldenrod3

  • darkgoldenrod4

  • rosybrown1

  • rosybrown2

  • rosybrown3

  • rosybrown4

  • indianred1

  • indianred2

  • indianred3

  • indianred4

  • sienna1

  • sienna2

  • sienna3

  • sienna4

  • burlywood1

  • burlywood2

  • burlywood3

  • burlywood4

  • wheat1

  • wheat2

  • wheat3

  • wheat4

  • tan1

  • tan2

  • tan3

  • tan4

  • chocolate1

  • chocolate2

  • chocolate3

  • chocolate4

  • firebrick1

  • firebrick2

  • firebrick3

  • firebrick4

  • brown1

  • brown2

  • brown3

  • brown4

  • salmon1

  • salmon2

  • salmon3

  • salmon4

  • lightsalmon1

  • lightsalmon2

  • lightsalmon3

  • lightsalmon4

  • orange1

  • orange2

  • orange3

  • orange4

  • darkorange1

  • darkorange2

  • darkorange3

  • darkorange4

  • coral1

  • coral2

  • coral3

  • coral4

  • tomato1

  • tomato2

  • tomato3

  • tomato4

  • orangered1

  • orangered2

  • orangered3

  • orangered4

  • red1

  • red2

  • red3

  • red4

  • debianred

  • deeppink1

  • deeppink2

  • deeppink3

  • deeppink4

  • hotpink1

  • hotpink2

  • hotpink3

  • hotpink4

  • pink1

  • pink2

  • pink3

  • pink4

  • lightpink1

  • lightpink2

  • lightpink3

  • lightpink4

  • palevioletred1

  • palevioletred2

  • palevioletred3

  • palevioletred4

  • maroon1

  • maroon2

  • maroon3

  • maroon4

  • violetred1

  • violetred2

  • violetred3

  • violetred4

  • magenta1

  • magenta2

  • magenta3

  • magenta4

  • orchid1

  • orchid2

  • orchid3

  • orchid4

  • plum1

  • plum2

  • plum3

  • plum4

  • mediumorchid1

  • mediumorchid2

  • mediumorchid3

  • mediumorchid4

  • darkorchid1

  • darkorchid2

  • darkorchid3

  • darkorchid4

  • purple1

  • purple2

  • purple3

  • purple4

  • mediumpurple1

  • mediumpurple2

  • mediumpurple3

  • mediumpurple4

  • thistle1

  • thistle2

  • thistle3

  • thistle4

  • gray0

  • grey0

  • gray1

  • grey1

  • gray2

  • grey2

  • gray3

  • grey3

  • gray4

  • grey4

  • gray5

  • grey5

  • gray6

  • grey6

  • gray7

  • grey7

  • gray8

  • grey8

  • gray9

  • grey9

  • gray10

  • grey10

  • gray11

  • grey11

  • gray12

  • grey12

  • gray13

  • grey13

  • gray14

  • grey14

  • gray15

  • grey15

  • gray16

  • grey16

  • gray17

  • grey17

  • gray18

  • grey18

  • gray19

  • grey19

  • gray20

  • grey20

  • gray21

  • grey21

  • gray22

  • grey22

  • gray23

  • grey23

  • gray24

  • grey24

  • gray25

  • grey25

  • gray26

  • grey26

  • gray27

  • grey27

  • gray28

  • grey28

  • gray29

  • grey29

  • gray30

  • grey30

  • gray31

  • grey31

  • gray32

  • grey32

  • gray33

  • grey33

  • gray34

  • grey34

  • gray35

  • grey35

  • gray36

  • grey36

  • gray37

  • grey37

  • gray38

  • grey38

  • gray39

  • grey39

  • gray40

  • grey40

  • gray41

  • grey41

  • gray42

  • grey42

  • gray43

  • grey43

  • gray44

  • grey44

  • gray45

  • grey45

  • gray46

  • grey46

  • gray47

  • grey47

  • gray48

  • grey48

  • gray49

  • grey49

  • gray50

  • grey50

  • gray51

  • grey51

  • gray52

  • grey52

  • gray53

  • grey53

  • gray54

  • grey54

  • gray55

  • grey55

  • gray56

  • grey56

  • gray57

  • grey57

  • gray58

  • grey58

  • gray59

  • grey59

  • gray60

  • grey60

  • gray61

  • grey61

  • gray62

  • grey62

  • gray63

  • grey63

  • gray64

  • grey64

  • gray65

  • grey65

  • gray66

  • grey66

  • gray67

  • grey67

  • gray68

  • grey68

  • gray69

  • grey69

  • gray70

  • grey70

  • gray71

  • grey71

  • gray72

  • grey72

  • gray73

  • grey73

  • gray74

  • grey74

  • gray75

  • grey75

  • gray76

  • grey76

  • gray77

  • grey77

  • gray78

  • grey78

  • gray79

  • grey79

  • gray80

  • grey80

  • gray81

  • grey81

  • gray82

  • grey82

  • gray83

  • grey83

  • gray84

  • grey84

  • gray85

  • grey85

  • gray86

  • grey86

  • gray87

  • grey87

  • gray88

  • grey88

  • gray89

  • grey89

  • gray90

  • grey90

  • gray91

  • grey91

  • gray92

  • grey92

  • gray93

  • grey93

  • gray94

  • grey94

  • gray95

  • grey95

  • gray96

  • grey96

  • gray97

  • grey97

  • gray98

  • grey98

  • gray99

  • grey99

  • gray100

  • grey100

  • darkgrey

  • darkgray

  • darkblue

  • darkcyan

  • darkmagenta

  • darkred

  • lightgreen

See Also#

See also

Reference#

Glossary#

Cli#

CLI#
command line interface#

A program executed at the command line with a text-based user interface.

GUI#
graphical user interface#

A program where users provide input primarily by manipulating visual elements. Examples include ATMs, Windows, MacOS, nearly all smartphones, web browsers, and office programs.

stdin#

The standard input file stream.

stdout#

The standard output file stream.

stderr#

The standard error file stream.

FD#
file descriptor#

A unique identifier associated with an input/output resource, most often a positive number.

environment variables#

A variable is set on the command line and effects how programs are run or behave.

exit code#
status code#

A number between 0 and 255 returned by command line programs to indicate success or failure.