791

In Python, how can we find out the command line arguments that were provided for a script, and process them?


Related background reading: What does "sys.argv[1]" mean? (What is sys.argv, and where does it come from?). For some more specific examples, see Implementing a "[command] [action] [parameter]" style command-line interfaces? and How do I format positional argument help using Python's optparse?.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
  • 6
    Use docopt (see @ralbatross's answer at http://stackoverflow.com/a/14790373/116891). I've tried every other way and, really, docopt is the only one I will use going forward. – Pat Oct 21 '13 at 02:50
  • 3
    I don't think there's one single best way. argparse is standard and featureful. docopt is very elegant but not in the standard library. For very easy lightweight use you can [make function default values handle comand line argument defaults for you](http://stackoverflow.com/a/43234054/318488). – Simon Hibbs Apr 05 '17 at 15:27

22 Answers22

679
import sys

print("\n".join(sys.argv))

sys.argv is a list that contains all the arguments passed to the script on the command line. sys.argv[0] is the script name.

Basically,

import sys
print(sys.argv[1:])
Timur Shtatland
  • 12,024
  • 2
  • 30
  • 47
John Slavick
  • 10,179
  • 5
  • 28
  • 25
  • 98
    For really simple stuff, this is the way to go, although you probably only want to use `sys.argv[1:]` (avoids the script name). – Xiong Chiamiov Sep 12 '10 at 07:31
597

The canonical solution in the standard library is argparse (docs):

Here is an example:

from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument("-f", "--file", dest="filename",
                    help="write report to FILE", metavar="FILE")
parser.add_argument("-q", "--quiet",
                    action="store_false", dest="verbose", default=True,
                    help="don't print status messages to stdout")

args = parser.parse_args()

argparse supports (among other things):

  • Multiple options in any order.
  • Short and long options.
  • Default values.
  • Generation of a usage help message.
wim
  • 338,267
  • 99
  • 616
  • 750
Ayman Hourieh
  • 132,184
  • 23
  • 144
  • 116
  • 4
    Are these built in modules the best? Or can you think of a better custom way? –  Jun 17 '09 at 22:42
  • 35
    Yes, these are the best. Since they're part of the standard library, you can be sure they'll be available and they're easy to use. optparse in particular is powerful and easy. – Barry Wark Jun 17 '09 at 22:43
  • 2
    @edgerA: What does "better custom way" mean? – S.Lott Jun 17 '09 at 23:29
  • 6
    optparse is one of the best; getopt is old and really ought to be considered deprecated. – jemfinch Apr 09 '10 at 20:49
  • 14
    at this point (12/2011), argparse is now considered a better option than optparse, correct? – oob Dec 20 '11 at 21:48
  • 63
    Python Documentation suggests the use of [argparse](http://docs.python.org/library/argparse.html#module-argparse) instead of optparse. – earthmeLon May 22 '12 at 15:45
  • 10
    Since `optparse` is deprecated, the asker of the question is no longer a member on stack overflow, and this is the accepted answer on a highly visible question - please consider completely rewriting your example code to use stdlib `argparse` instead. – wim May 23 '18 at 17:13
  • 4
    @AymanHourieh you did not show how to get those arguments. The documentation of this module is a mess. – r.mirzojonov Aug 01 '19 at 00:12
132

Just going around evangelizing for argparse which is better for these reasons.. essentially:

(copied from the link)

  • argparse module can handle positional and optional arguments, while optparse can handle only optional arguments

  • argparse isn’t dogmatic about what your command line interface should look like - options like -file or /file are supported, as are required options. Optparse refuses to support these features, preferring purity over practicality

  • argparse produces more informative usage messages, including command-line usage determined from your arguments, and help messages for both positional and optional arguments. The optparse module requires you to write your own usage string, and has no way to display help for positional arguments.

  • argparse supports action that consume a variable number of command-line args, while optparse requires that the exact number of arguments (e.g. 1, 2, or 3) be known in advance

  • argparse supports parsers that dispatch to sub-commands, while optparse requires setting allow_interspersed_args and doing the parser dispatch manually

And my personal favorite:

  • argparse allows the type and action parameters to add_argument() to be specified with simple callables, while optparse requires hacking class attributes like STORE_ACTIONS or CHECK_METHODS to get proper argument checking
Silfheed
  • 11,585
  • 11
  • 55
  • 67
  • 30
    This is now part of standard Python as of 2.7 and 3.2 :) – jpswain Sep 03 '10 at 02:08
  • 2
    What are "optional arguments"? You say they're in optparse. I thought that they were arguments that may or may not be provided, but you said they're in optparse while going on to say that "optparse requires that the exact number of arguments be known in advance". So either your definition of "optional argument" differs from what I thought, or your answer is inconsistent with itself. – ArtOfWarfare Aug 07 '14 at 12:44
  • 4
    Just a gripe: argparse documentation is also insanely, insanely complicated. You can't get a simple answer for "how do I make a command line argument take in a single value, and how do I access that value." – osman Apr 13 '17 at 19:09
  • 6
    @osman This gentle [tutorial](https://docs.python.org/3/howto/argparse.html) on argparse might help... – lifebalance Jun 13 '17 at 15:51
  • 4
    @ArtOfWarfare "optional arguments" in this context presumably means arguments specified with option-like arguments such as `-f` or `--foo`, while "exact number of arguments be known in advance" presumably means positional arguments given without any preceding option flags. – mtraceur Jul 25 '18 at 23:55
77

There is also argparse stdlib module (an "impovement" on stdlib's optparse module). Example from the introduction to argparse:

# script.py
import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'integers', metavar='int', type=int, choices=range(10),
         nargs='+', help='an integer in the range 0..9')
    parser.add_argument(
        '--sum', dest='accumulate', action='store_const', const=sum,
        default=max, help='sum the integers (default: find the max)')

    args = parser.parse_args()
    print(args.accumulate(args.integers))

Usage:

$ script.py 1 2 3 4
4

$ script.py --sum 1 2 3 4
10
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • 3
    its just a copy and paste – blitu12345 Jun 16 '18 at 10:20
  • 7
    @blitu12345 at the time of the publication of my answer there were no other answers that mention argparse in any way. The module itself was not in stdlib¶ What do you have against code examples from the documentation? Why do you think it is necessary to come up with your own examples instead of examples provided by the author of the module? And I don't like link-only answers (I'm not alone). – jfs Jun 20 '18 at 14:44
  • 3
    Peoples coming here already had an idea whats in the documentation and will be here only for further clearance about the topic.Same was my case but what i really found here is a copy and paste from the original docs.Peace! – blitu12345 Jun 20 '18 at 17:04
  • 13
    "Peoples coming here already had an idea whats in the documentation" - i _highly_ doubt that assumtion. somehow. – sjas Dec 20 '18 at 22:02
  • 2
    I found it difficult to figure out how to actually use the results of the parsing. In this answer, this is addressed in the last line of code (so +1). But to be honest, this example is very compact and probably far beyond the capabilities of people asking about processing command line arguments. – Wolf Sep 08 '22 at 11:10
73

If you need something fast and not very flexible

main.py:

import sys

first_name = sys.argv[1]
last_name = sys.argv[2]
print("Hello " + first_name + " " + last_name)

Then run python main.py James Smith

to produce the following output:

Hello James Smith

Kent Munthe Caspersen
  • 5,918
  • 1
  • 35
  • 34
  • A more realistic usage would be `python main.py "James Smith"` which puts `James Smith` in `sys.argv[1]` and produces an `IndexError` when you try to use the nonexistent `sys.argv[2]`. Quoting behavior will somewhat depend on which platform and shell you run Python from. – tripleee Dec 22 '17 at 08:02
  • 14
    I don't agree that my usage is less realistic. Pretend your program needs to know the exact first and last name of a person to run the script in a business where people can have multiple first and last names? If James Smith has Joseph as an extra first or last name, how would distinguish between whether Joseph is an extra first or last name if you only do `python main.py "James Joseph Smith"`? If you are concerned with index out of bounds, you can add a check for the number of provided arguments. Less realistic or not, my example shows how to handle multiple arguments. – Kent Munthe Caspersen Jan 01 '18 at 19:55
  • 5
    All the other answers are for plotting a lunar landing mission. I'm just simply using `gmail-trash-msg.py MessageID`. This answer is straight forward to test `MessageID` parameter has been passed in `sys.argv[1]`. – WinEunuuchs2Unix May 22 '19 at 23:27
53

One way to do it is using sys.argv. This will print the script name as the first argument and all the other parameters that you pass to it.

import sys

for arg in sys.argv:
    print arg
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JPCosta
  • 1,237
  • 10
  • 15
53

The docopt library is really slick. It builds an argument dict from the usage string for your app.

Eg from the docopt readme:

"""Naval Fate.

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='Naval Fate 2.0')
    print(arguments)
ralbatross
  • 2,448
  • 4
  • 25
  • 45
  • 5
    This has rapidly become my favorite way to go. It's string parsing so it's kind of brittle, but it's brittle _all in one place_ and you can preview your logic at http://try.docopt.org . Optional and mutually-exclusive arguments are done in a really elegant way. – gvoysey Mar 29 '16 at 03:34
27
#set default args as -h , if no args:
if len(sys.argv) == 1: sys.argv[1:] = ["-h"]
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
whi
  • 2,685
  • 6
  • 33
  • 40
20

I use optparse myself, but really like the direction Simon Willison is taking with his recently introduced optfunc library. It works by:

"introspecting a function definition (including its arguments and their default values) and using that to construct a command line argument parser."

So, for example, this function definition:

def geocode(s, api_key='', geocoder='google', list_geocoders=False):

is turned into this optparse help text:

    Options:
      -h, --help            show this help message and exit
      -l, --list-geocoders
      -a API_KEY, --api-key=API_KEY
      -g GEOCODER, --geocoder=GEOCODER
Van Gale
  • 43,536
  • 9
  • 71
  • 81
9

I like getopt from stdlib, eg:

try:
    opts, args = getopt.getopt(sys.argv[1:], 'h', ['help'])
except getopt.GetoptError, err: 
    usage(err)

for opt, arg in opts:
    if opt in ('-h', '--help'): 
        usage()

if len(args) != 1:
    usage("specify thing...")

Lately I have been wrapping something similiar to this to make things less verbose (eg; making "-h" implicit).

Peter Ericson
  • 1,889
  • 1
  • 12
  • 4
9

Pocoo's click is more intuitive, requires less boilerplate, and is at least as powerful as argparse.

The only weakness I've encountered so far is that you can't do much customization to help pages, but that usually isn't a requirement and docopt seems like the clear choice when it is.

Ryne Everett
  • 6,427
  • 3
  • 37
  • 49
8

As you can see optparse "The optparse module is deprecated with and will not be developed further; development will continue with the argparse module."

tverrbjelke
  • 1,234
  • 10
  • 15
6
import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                   help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
                   const=sum, default=max,
                   help='sum the integers (default: find the max)')

args = parser.parse_args()
print(args.accumulate(args.integers))

Assuming the Python code above is saved into a file called prog.py
$ python prog.py -h

Ref-link: https://docs.python.org/3.3/library/argparse.html
JON
  • 1,668
  • 2
  • 15
  • 18
5

Yet another option is argh. It builds on argparse, and lets you write things like:

import argh

# declaring:

def echo(text):
    "Returns given word as is."
    return text

def greet(name, greeting='Hello'):
    "Greets the user with given name. The greeting is customizable."
    return greeting + ', ' + name

# assembling:

parser = argh.ArghParser()
parser.add_commands([echo, greet])

# dispatching:

if __name__ == '__main__':
    parser.dispatch()

It will automatically generate help and so on, and you can use decorators to provide extra guidance on how the arg-parsing should work.

circular-ruin
  • 2,834
  • 1
  • 24
  • 30
  • 1
    This is the best solution. Using `argh` is easier than another libs or using `sys`. – Juanjo Salvador Jun 24 '17 at 10:00
  • 1
    I wanted to like `argh` but it's not particularly suitable for scenarios where your utmost desire is not to have a command with subcommands. – tripleee Dec 22 '17 at 08:04
  • 2
    @tripleee YMMV, but I found that this was more of a defect in the documentation than in the library itself. It seems perfectly feasible to have `def frobnicate_spleches(...)` defining a function that does whatever your script does, then doing `if __name__ == '__main__': argh.dispatch_command(frobnicate_spleches)` at the end of the file. – circular-ruin Feb 06 '18 at 19:16
5

You may be interested in a little Python module I wrote to make handling of command line arguments even easier (open source and free to use) - Commando

Mufasa
  • 51
  • 2
  • 1
4

I recommend looking at docopt as a simple alternative to these others.

docopt is a new project that works by parsing your --help usage message rather than requiring you to implement everything yourself. You just have to put your usage message in the POSIX format.

David C. Bishop
  • 6,437
  • 3
  • 28
  • 22
3

Also with python3 you might find convenient to use Extended Iterable Unpacking to handle optional positional arguments without additional dependencies:

try:
   _, arg1, arg2, arg3, *_ = sys.argv + [None] * 2
except ValueError:
   print("Not enough arguments", file=sys.stderr) # unhandled exception traceback is meaningful enough also
   exit(-1)

The above argv unpack makes arg2 and arg3 "optional" - if they are not specified in argv, they will be None, while if the first is not specified, ValueError will be thouwn:

Traceback (most recent call last):
  File "test.py", line 3, in <module>
    _, arg1, arg2, arg3, *_ = sys.argv + [None] * 2
ValueError: not enough values to unpack (expected at least 4, got 3)
Volodymyr Boiko
  • 1,533
  • 15
  • 29
3

Reason for the new answer:

  1. Existing answers specify multiple options.
  2. Standard option is to use argparse, a few answers provided examples from the documentation, and one answer suggested the advantage of it. But all fail to explain the answer adequately/clearly to the actual question by OP, at least for newbies.

An example of argparse:

import argparse


def load_config(conf_file):
    pass


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    //Specifies one argument from the command line
    //You can have any number of arguments like this
    parser.add_argument("conf_file", help="configuration file for the application") 
    args = parser.parse_args()
    config = load_config(args.conf_file)

Above program expects a config file as an argument. If you provide it, it will execute happily. If not, it will print the following

usage: test.py [-h] conf_file
test.py: error: the following arguments are required: conf_file
  • You can have the option to specify if the argument is optional.

  • You can specify the expected type for the argument using type key

    parser.add_argument("age", type=int, help="age of the person")

  • You can specify default value for the arguments by specifying default key

This document will help you to understand it to an extent.

Gibbs
  • 21,904
  • 13
  • 74
  • 138
1
import sys

# Command line arguments are stored into sys.argv
# print(sys.argv[1:])

# I used the slice [1:] to print all the elements except the first
# This because the first element of sys.argv is the program name
# So the first argument is sys.argv[1], the second is sys.argv[2] ecc

print("File name: " + sys.argv[0])
print("Arguments:")
for i in sys.argv[1:]:
    print(i)

Let's name this file command_line.py and let's run it:

C:\Users\simone> python command_line.py arg1 arg2 arg3 ecc
File name: command_line.py
Arguments:
arg1
arg2
arg3
ecc

Now let's write a simple program, sum.py:

import sys

try:
    print(sum(map(float, sys.argv[1:])))
except:
    print("An error has occurred")

Result:

C:\Users\simone> python sum.py 10 4 6 3
23
SimCop07
  • 31
  • 2
0

Several of our biotechnology clients have posed these two questions recently:

  • How can we execute a Python script as a command?
  • How can we pass input values to a Python script when it is executed as a command?

I have included a Python script below which I believe answers both questions. Let's assume the following Python script is saved in the file test.py:

#
#----------------------------------------------------------------------
#
# file name: test.py
#
# input values: data  - location of data to be processed
#               date  - date data were delivered for processing
#               study - name of the study where data originated
#               logs  - location where log files should be written 
#
# macOS usage: 
#
#   python3 test.py "/Users/lawrence/data" "20220518" "XYZ123" "/Users/lawrence/logs"
#
# Windows usage: 
#
#   python test.py "D:\data" "20220518" "XYZ123" "D:\logs"
#
#----------------------------------------------------------------------
#
# import needed modules...
#
import sys
import datetime

def main(argv):

   #
   # print message that process is starting...
   #
   print("test process starting at", datetime.datetime.now().strftime("%Y%m%d %H:%M"))

   #
   # set local values from input values...
   #
   data = sys.argv[1]
   date = sys.argv[2]
   study = sys.argv[3]
   logs = sys.argv[4]

   #
   # print input arguments...
   #
   print("data value is", data)
   print("date value is", date)
   print("study value is", study)
   print("logs value is", logs)

   #
   # print message that process is ending...
   #
   print("test process ending at", datetime.datetime.now().strftime("%Y%m%d %H:%M"))

#
# call main() to begin processing...
#

if __name__ == '__main__':

   main(sys.argv)

The script can be executed on a macOS computer in a Terminal shell as shown below and the results will be printed to standard output (be sure the current directory includes the test.py file):

$ python3 test.py "/Users/lawrence/data" "20220518" "XYZ123" "/Users/lawrence/logs"
test process starting at 20220518 16:51
data value is /Users/lawrence/data
date value is 20220518
study value is XYZ123
logs value is /Users/lawrence/logs
test process ending at 20220518 16:51

The script can also be executed on a Windows computer in a Command Prompt as shown below and the results will be printed to standard output (be sure the current directory includes the test.py file):

D:\scripts>python test.py "D:\data" "20220518" "XYZ123" "D:\logs"
test process starting at 20220518 17:20
data value is D:\data
date value is 20220518
study value is XYZ123
logs value is D:\logs
test process ending at 20220518 17:20

This script answers both questions posed above and is a good starting point for developing scripts that will be executed as commands with input values.

0

This handles simple switches, value switches with optional alternative flags.

import sys

# [IN] argv - array of args
# [IN] switch - switch to seek
# [IN] val - expecting value
# [IN] alt - switch alternative
# returns value or True if val not expected
def parse_cmd(argv,switch,val=None,alt=None):
    for idx, x in enumerate(argv):
        if x == switch or x == alt:
            if val:
                if len(argv) > (idx+1):            
                    if not argv[idx+1].startswith('-'):
                        return argv[idx+1]
            else:
                return True

//expecting a value for -i
i = parse_cmd(sys.argv[1:],"-i", True, "--input")

//no value needed for -p
p = parse_cmd(sys.argv[1:],"-p")
O Wigley
  • 157
  • 1
  • 4
0

My solution is entrypoint2. Example:

from entrypoint2 import entrypoint
@entrypoint
def add(file, quiet=True): 
    ''' This function writes report.

    :param file: write report to FILE
    :param quiet: don't print status messages to stdout
    '''
    print file,quiet

help text:

usage: report.py [-h] [-q] [--debug] file

This function writes report.

positional arguments:
  file         write report to FILE

optional arguments:
  -h, --help   show this help message and exit
  -q, --quiet  don't print status messages to stdout
  --debug      set logging level to DEBUG
ponty
  • 614
  • 8
  • 8