Skip to content

ይህ ትምህርት ገና ወደ አማርኛ አልተተረጎመም፤ ስለዚህ በእንግሊዝኛ ቀርቧል። የእንግሊዝኛውን ገጽ ክፈቱ

Command-line programs

4 min read

So far your programs ask for what they need with input(). Real tools often take their instructions from the command that starts them instead: python ledger.py add 250 food does the whole job in one line, with no questions. By the end of this lesson you'll read those words in your program, let argparse check them, and end with an exit code that says whether it worked.

Reading the command

When you start a program in a terminal, the words after its name are its . Python puts the whole command, without python, in the list sys.argv. The runner below shows its command above the code, and you can edit the words after ledger.py:

import sys

print(sys.argv)
print(sys.argv[0])
print(sys.argv[1])

In the editor, press Escape then Tab to move on.

sys.argv[0] is the script's own name, and the arguments start at sys.argv[1]. Spaces separate them; to pass words with a space as one argument, put them in quotes: "ቡና ጠጣሁ". Try it in the command line.

Now a program that doubles a number from its command. Predict:

ውጤቱን ገምቱ

Decide before you look. Guessing wrong is how this sticks.

import sys

print(sys.argv[1] * 2)

Command

python double.py 250

Pick the output

Python prints

250250

sys.argv is a list of strings. '250' * 2 repeats the text, as in lesson 1.3. Convert with int() first.

If you said 500, you read 250 as a number. Every argument is text, like input() gives you, and * repeats text. If you said TypeError, multiplying text by a number is allowed; it's adding them that isn't. Use int(sys.argv[1]).

ጥያቄ

For the command python ledger.py add 250, what is sys.argv[0]?

Choosing what to do

A match (lesson 2.5) on the first argument picks the command:

import sys

match sys.argv[1]:
    case "add":
        print("Adding", sys.argv[2], "birr")
    case "list":
        print("Listing expenses")
    case _:
        print("Unknown command:", sys.argv[1])

In the editor, press Escape then Tab to move on.

Change the command to ledger.py list, then to ledger.py remove. Then delete every argument and run python ledger.py alone:

Checking every argument by hand gets long fast. That's what argparse is for.

argparse

argparse, in the standard library, reads the arguments for you. You describe each one, and it converts the types, checks that nothing is missing, and writes a help message. Run this, then change the command:

import argparse

parser = argparse.ArgumentParser(description="Record an expense.")
parser.add_argument("amount", type=int, help="the amount in birr")
parser.add_argument("category", help="what it was for")
args = parser.parse_args()
print(f"Adding {args.amount} birr for {args.category}")
print(type(args.amount))

In the editor, press Escape then Tab to move on.

args.amount is already an int: type=int converted it. Here is the same program started with ledger.py --help. The help is written for you from your descriptions:

import argparse

parser = argparse.ArgumentParser(description="Record an expense.")
parser.add_argument("amount", type=int, help="the amount in birr")
parser.add_argument("category", help="what it was for")
args = parser.parse_args()
print(f"Adding {args.amount} birr for {args.category}")

In the editor, press Escape then Tab to move on.

Under the help, the runner says Program ended (exit code 0). Change the command to ledger.py lots food and run it: argparse prints the usage and ledger.py: error: argument amount: invalid int value: 'lots', and the program ends with exit code 2. Neither is a crash: argparse ends the program on purpose.

Exit codes

Every program ends with an , a number for whatever started it: 0 means "it worked", anything else means "something went wrong". A program that runs to the end exits with 0; one stopped by an error nothing caught, with a traceback, exits with 1. sys.exit() ends it early: sys.exit(1) with code 1, and sys.exit("message") prints the message as an error and exits with 1.

import sys

amount = int(sys.argv[1])
if amount <= 0:
    sys.exit("Amount must be more than 0.")
print("Adding", amount)

In the editor, press Escape then Tab to move on.

It shows the message and Program ended (exit code 1). Why care? Other programs read the code. A script that runs your ledger every night, or a test tool in Module 9, checks for 0 to know whether to carry on.

On your computer, the same programs run in a terminal from the script's folder, with python3 instead of python on macOS and Linux (lesson 0.4):

python ledger.py 250 food
python ledger.py --help

መልመጃ

Birr to santim

Write convert.py: it reads an amount in birr from its command and prints it in santim (100 santim to a birr), rounded to a whole number. The command is python convert.py 12.5.

Output
1250 santim

Your code

import sys

# Read the amount from sys.argv, convert it, and print it in santim

In the editor, press Escape then Tab to move on.

መፍትሄውን አሳይ

This is one way to solve it, not the only one. If yours prints the same thing, it works.

import sys

birr = float(sys.argv[1])
print(round(birr * 100), "santim")

ዋና ዋና ነጥቦች

  • sys.argv is the command as a list of strings: sys.argv[0] is the script's name, the arguments follow.
  • Every argument is text: convert it with int() or float(), and check there are enough before using them.
  • argparse converts types, checks what's missing, and writes --help for you.
  • An exit code of 0 means success; sys.exit("message") ends with code 1. argparse exits with 0 for --help and 2 for bad arguments.