¿Cómo leer / procesar argumentos de línea de comando?

625

Originalmente soy un programador C. He visto numerosos trucos y "hacks" para leer muchos argumentos diferentes.

¿Cuáles son algunas de las formas en que los programadores de Python pueden hacer esto?

Relacionado

Martineau
fuente
55
Use docopt (consulte la respuesta de @ ralbatross en stackoverflow.com/a/14790373/116891 ). Lo he intentado de cualquier otra manera y, realmente, docopt es el único que usaré en el futuro.
Pat
2
No creo que haya una sola mejor manera. argparse es estándar y funcional. docopt es muy elegante pero no está en la biblioteca estándar. Para un uso liviano muy fácil, puede hacer que los valores predeterminados de la función manejen los valores predeterminados de los argumentos de línea y com para usted .
Simon Hibbs

Respuestas:

457

La solución canónica en la biblioteca estándar es argparse( docs ):

Aquí hay un ejemplo:

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 soportes (entre otras cosas):

  • Múltiples opciones en cualquier orden.
  • Opciones cortas y largas.
  • Valores predeterminados.
  • Generación de un mensaje de ayuda de uso.
Ayman Hourieh
fuente
27
Sí, estos son los mejores. Como forman parte de la biblioteca estándar, puede estar seguro de que estarán disponibles y son fáciles de usar. optparse en particular es potente y fácil.
Barry Wark
44
optparse es uno de los mejores; getopt es viejo y realmente debería considerarse obsoleto.
jemfinch
12
en este punto (12/2011), argparse ahora se considera una mejor opción que optparse, ¿correcto?
oob
54
La documentación de Python sugiere el uso de argparse en lugar de optparse.
earthmeLon
77
Dado que optparseestá en desuso, el autor de la pregunta ya no es miembro del desbordamiento de la pila, y esta es la respuesta aceptada en una pregunta muy visible; considere reescribir completamente su código de ejemplo para utilizar stdlib argparse.
wim
548
import sys

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

sys.argv es una lista que contiene todos los argumentos pasados ​​al script en la línea de comando.

Básicamente,

import sys
print(sys.argv[1:])
John Slavick
fuente
83
Para cosas realmente simples, este es el camino a seguir, aunque probablemente solo desee usar sys.argv[1:](evita el nombre del script).
Xiong Chiamiov
128

Simplemente dando vueltas evangelizando por argparse, lo cual es mejor por estas razones ... esencialmente:

(copiado del enlace)

  • El módulo argparse puede manejar argumentos posicionales y opcionales, mientras que optparse solo puede manejar argumentos opcionales

  • argparse no es dogmático sobre el aspecto que debería tener su interfaz de línea de comandos: se admiten opciones como -file o / file, al igual que las opciones requeridas. Optparse se niega a admitir estas características, prefiriendo la pureza sobre la practicidad

  • argparse produce mensajes de uso más informativos, incluido el uso de línea de comandos determinado a partir de sus argumentos, y mensajes de ayuda para argumentos posicionales y opcionales. El módulo optparse requiere que escriba su propia cadena de uso, y no tiene forma de mostrar ayuda para argumentos posicionales.

  • argparse admite acciones que consumen un número variable de argumentos de línea de comandos, mientras que optparse requiere que se conozca de antemano el número exacto de argumentos (por ejemplo, 1, 2 o 3)

  • argparse admite analizadores que se envían a subcomandos, mientras que optparse requiere configurar allow_interspersed_argsy realizar el envío de analizador manualmente

Y mi favorito personal:

  • argparse permite que los parámetros de tipo y acción add_argument() se especifiquen con cálculos simples, mientras que optparse requiere la piratería de atributos de clase como STORE_ACTIONSo CHECK_METHODSpara obtener una verificación de argumento adecuada
Silfheed
fuente
27
Esto ahora es parte de Python estándar a partir de 2.7 y 3.2 :)
jpswain
¿Qué son los "argumentos opcionales"? Dices que están en optparse. Pensé que eran argumentos que pueden proporcionarse o no, pero usted dijo que están en optparse al decir que "optparse requiere que se conozca de antemano el número exacto de argumentos". Entonces, su definición de "argumento opcional" difiere de lo que pensaba, o su respuesta es inconsistente consigo misma.
ArtOfWarfare
1
Solo una queja: la documentación argparse también es increíblemente complicada. No puede obtener una respuesta simple para "cómo hago que un argumento de línea de comando tome un solo valor y cómo accedo a ese valor". </gripe>
osman
2
@osman Este amable tutorial sobre argparse podría ayudar ...
lifebalance
2
@ArtOfWarfare "argumentos opcionales" en este contexto presumiblemente significa argumentos especificados con argumentos similares a las opciones tales como -fo --foo, mientras que "se conoce de antemano el número exacto de argumentos" presumiblemente significa argumentos posicionales dados sin ningún indicador de opción anterior.
mtraceur
67

También hay argparseun módulo stdlib (una "mejora" en el optparsemódulo stdlib ). Ejemplo de la introducción a 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))

Uso:

$ script.py 1 2 3 4
4

$ script.py --sum 1 2 3 4
10
jfs
fuente
1
es solo copiar y pegar
blitu12345
3
@ blitu12345 en el momento de la publicación de mi respuesta, no había otras respuestas que mencionaran argparse de ninguna manera. El módulo en sí no estaba en stdlib¶ ¿Qué tienes contra los ejemplos de código de la documentación? ¿Por qué crees que es necesario crear tus propios ejemplos en lugar de los ejemplos proporcionados por el autor del módulo? Y no me gustan las respuestas de solo enlace (no estoy solo).
jfs
1
Las personas que vienen aquí ya tenían una idea de lo que hay en la documentación y estarán aquí solo para obtener más información sobre el tema. Lo mismo fue mi caso, pero lo que realmente encontré aquí es copiar y pegar de los documentos originales. ¡Paz!
blitu12345
2
"Los pueblos que vienen aquí ya tenían una idea de lo que hay en la documentación". Dudo mucho esa suposición. de algun modo.
sjas
49

Una forma de hacerlo es usando sys.argv. Esto imprimirá el nombre del script como primer argumento y todos los demás parámetros que le pase.

import sys

for arg in sys.argv:
    print arg
JPCosta
fuente
49

La biblioteca docopt es realmente elegante. Construye un argumento dict a partir de la cadena de uso para su aplicación.

Por ejemplo, del archivo Léame de docopt:

"""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)
ralbatros
fuente
44
Esto se ha convertido rápidamente en mi camino favorito. Es un análisis de cadenas, por lo que es un poco frágil, pero es frágil en un solo lugar y puede previsualizar su lógica en try.docopt.org . Los argumentos opcionales y mutuamente excluyentes se realizan de una manera realmente elegante.
gvoysey
44
Estoy desesperado por ver el resto del código de naval_fate.py
John Lawrence Aspden
48

Si necesitas algo rápido y no muy flexible

main.py:

import sys

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

Entonces corre python main.py James Smith

para producir el siguiente resultado:

Hola james smith

Kent Munthe Caspersen
fuente
Un uso más realista sería python main.py "James Smith"que pone James Smithen sys.argv[1]y produce una IndexErrorcuando intenta utilizar la inexistente sys.argv[2]. El comportamiento de las citas dependerá un poco de la plataforma y el shell desde el que ejecute Python.
tripleee
10
No estoy de acuerdo con que mi uso sea menos realista. ¿Pretende que su programa necesita saber el nombre y apellido exactos de una persona para ejecutar el script en un negocio donde las personas pueden tener múltiples nombres y apellidos? Si James Smith tiene a Joseph como nombre o apellido extra, ¿cómo distinguiría si Joseph es un nombre o apellido extra si solo lo hace python main.py "James Joseph Smith"? Si le preocupa el índice fuera de los límites, puede agregar una verificación para la cantidad de argumentos proporcionados. Menos realista o no, mi ejemplo muestra cómo manejar múltiples argumentos.
Kent Munthe Caspersen
1
Todas las otras respuestas son para planear una misión de aterrizaje lunar. Simplemente estoy usando gmail-trash-msg.py MessageID. Esta respuesta es directa al MessageIDparámetro de prueba que se ha pasado sys.argv[1].
WinEunuuchs2Unix
26
#set default args as -h , if no args:
if len(sys.argv) == 1: sys.argv[1:] = ["-h"]
whi
fuente
19

Yo mismo uso optparse, pero me gusta mucho la dirección que está tomando Simon Willison con su biblioteca optfunc recientemente presentada . Funciona por:

"introspección de una definición de función (incluidos sus argumentos y sus valores predeterminados) y usarla para construir un analizador de argumentos de línea de comando".

Entonces, por ejemplo, esta definición de función:

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

se convierte en este texto de ayuda de optparse:

    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
fuente
8

Me gusta getopt de stdlib, por ejemplo:

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...")

Últimamente he estado envolviendo algo similar a esto para hacer las cosas menos detalladas (por ejemplo, hacer "-h" implícito).

Peter Ericson
fuente
8

El clic de Pocoo es más intuitivo, requiere menos repetitivo y es al menos tan poderoso como argparse.

La única debilidad que he encontrado hasta ahora es que no se puede hacer mucha personalización para ayudar a las páginas, pero eso generalmente no es un requisito y docopt parece ser la opción clara cuando lo es.

Ryne Everett
fuente
7

Como puede ver optparse "El módulo optparse está en desuso y no se desarrollará más; el desarrollo continuará con el módulo argparse ".

tverrbjelke
fuente
5
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
fuente
4

Puede que le interese un pequeño módulo de Python que escribí para facilitar aún más el manejo de los argumentos de la línea de comandos (código abierto y uso gratuito) - Comando

Mufasa
fuente
1
Ya hay otro módulo de análisis de línea de comandos llamado Comando: github.com/lakshmivyas/commando . Envuelve argparse mediante el uso de decoradores.
Roberto Bonvallet
1
pitón y la rueda de re-invención
Derek
4

Recomiendo mirar docopt como una alternativa simple a estos otros.

docopt es un nuevo proyecto que funciona analizando su mensaje de ayuda en lugar de requerir que implemente todo usted mismo. Solo tiene que poner su mensaje de uso en el formato POSIX.

David C. Bishop
fuente
4

Otra opción más es argh . Se basa en argparse y te permite escribir cosas como:

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()

Generará automáticamente ayuda, etc., y puede usar decoradores para proporcionar orientación adicional sobre cómo debería funcionar el análisis de argumentos.

ruina circular
fuente
Esta es la mejor solución. Usar arghes más fácil que otras bibliotecas o usar sys.
Juanjo Salvador
Quería que me gustara, arghpero no es particularmente adecuado para escenarios en los que su mayor deseo es no tener un comando con subcomandos.
tripleee
1
@tripleee YMMV, pero descubrí que esto era más un defecto en la documentación que en la biblioteca misma. Parece perfectamente factible def frobnicate_spleches(...)definir una función que haga lo que haga su script y luego lo haga if __name__ == '__main__': argh.dispatch_command(frobnicate_spleches)al final del archivo.
ruina circular
0

Mi solución es entrypoint2 . Ejemplo:

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

texto de ayuda:

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
fuente