I do not like to write a python cli that accepts argument as I am an advocate of using wizard style to guide user on how to configure things easily. But it seems the time has come for me to write a CLI script in python, and in order to provide usage guide and data parsing i need to use the python’s argparse module.

stdin arguments

You can write a script without the need to parse, you need to import sys then use its argv method to get the arguments.
argv is a list, index 0 is argv[0] is the script name, argv[1] is the first argument, then argv[2] is the next and so on.

This is a sample code to send commands to Cisco asa with netmiko:

from netmiko import ConnectHandler
import sys

asa_config = dict(

with ConnectHandler(**asa_config) as asa:
    result = asa.send_command(sys.argv[4])

The usage will be this:
python asacmd2.py admin P@ssw0rd "sh int ip brief"

What bad about this is there is no “option” to remind user what are the positional arguments, and yes it is positional arguments, means I need to remember the first argument is username, second is password third is ip address and last is the command i need to send with netmiko.

And if there is no argument sent, python complains:

Traceback (most recent call last):
  File "asacmd2.py", line 5, in 
IndexError: list index out of range

And there is no help message on what i need to put in as arguments.

Parse the arguments with keyword options

So an improvement over the previous code will be using argparse, where i can add the argument and pass the data into a dest, and refer to the data like I am using a method.

So here’s the code:

from netmiko import ConnectHandler
from argparse import ArgumentParser
import sys

# arg parser configuration
parser = ArgumentParser(prog="asa command line tool", description="asa command line tool",
                        usage="python3 asacmd.py -u admin -p password -d -c \"show int ip brief\"")
parser.add_argument("-u", "--user", help="Username of device.", type=str, dest="user", required=True)
parser.add_argument("-p", "--pass", help="password", type=str, dest="password", required=True)
parser.add_argument("-d", "--device", help="IP address of cisco asa", type=str, dest="device", required=True)
parser.add_argument("-c", "--cmd", help="cisco asa command", type=str, dest="cmd", required=True)
parser.add_argument("--port", help="ssh port if not define it is 22 by default.", type=int, dest="port")

# https://stackoverflow.com/questions/4042452/display-help-message-with-python-argparse-when-script-is-called-without-any-argu
# if no argument is supplied print help message.
if len(sys.argv) == 1:
args = parser.parse_args()

# netmiko configuration
asa_config = dict(
    port=args.port if args.port else 22

with ConnectHandler(**asa_config) as asa:
    result = asa.send_command(args.cmd)

# print out the result

With argparse I do not need to remember the position as the switch in the cli is my keyword for me to supply the value, an example:
python asacmd.py -p P@ssw0rd -d -u admin -c "show int ip brief"

Notice the position does not matter, the switch itself provides a key for the value to be put in by user.

If I cannot remember the switch, I will do python asacmd.py -h

usage: python3 asacmd.py -u admin -p password -d -c "show int ip brief"

asa command line tool

optional arguments:
  -h, --help            show this help message and exit
  -u USER, --user USER  Username of device.
  -d DEVICE, --device DEVICE
                        IP address of cisco asa
  -c CMD, --cmd CMD     cisco asa command
  --port PORT           ssh port if not define it is 22 by default.

And if I do not supply any switch, the script will complain in a more helpful way:

If I supplied the wrong switch, the usage example can give user an idea on how to use like this:


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s