Argumentos de la línea de comandos en Python

General

Dado que Python es un lenguaje de programación muy popular, además de ser compatible con la mayoría de los sistemas operativos y muchas bibliotecas que facilitan el procesamiento de argumentos de la línea de comandos, se ha vuelto ampliamente utilizado para crear herramientas de línea de comandos para muchos propósitos. Estas herramientas pueden variar desde aplicaciones CLI simples hasta aplicaciones más complejas, como AWS. awscli .

Herramientas complejas como ésta normalmente son controladas por el usuario a través de argumentos de la línea de comando, que permite al usuario utilizar comandos específicos, configurar opciones y más. Por ejemplo, estas opciones podrían indicarle a la herramienta que genere información adicional, lea datos de una fuente específica o envíe resultados a una ubicación determinada.

En general, los argumentos se pasan a las herramientas CLI de forma diferente, según su sistema operativo:

  • Similar a Unix: - seguido de una letra, como -ho -- seguido de una palabra, como --help
  • ventanas: / seguido de una letra o palabra, como /help

Estos diferentes enfoques existen debido a razones históricas. Muchos programas en sistemas tipo Unix admiten la notación de guión simple y doble. La notación de guión único se usa principalmente con opciones de una sola letra, mientras que los guiones dobles presentan una lista de opciones más legible, lo cual es particularmente útil para opciones complejas que necesitan ser más explícitas.

Note: En este artículo nos centraremos únicamente en el formato tipo Unix de - y --.

Tenga en cuenta que tanto el nombre como el significado de un argumento son específicos de un programa; no existe una definición general, aparte de algunas convenciones comunes como --help para obtener más información sobre el uso de la herramienta. Como desarrollador de un script de Python, usted decidirá qué argumentos proporcionar a la persona que llama y qué hace. Esto requiere una evaluación adecuada.

A medida que su lista de argumentos disponibles crezca, su código se volverá más complejo al intentar analizarlos con precisión. Afortunadamente, en Python hay varias bibliotecas disponibles para ayudarte con esto. Cubriremos algunas de las soluciones más comunes, que van desde "hágalo usted mismo" con sys.argv, al enfoque "hecho para usted" con argparse.

Manejo de argumentos de línea de comando con Python

Python 3+ y el ecosistema que lo rodea admiten varias formas diferentes de manejar los argumentos de la línea de comandos. Hay muchos bibliotecas que facilitan el análisis de argumentos de línea de comandos.

La forma integrada es utilizar el sys módulo. En términos de nombres y su uso, se relaciona directamente con la biblioteca C (libc).

La segunda forma es la getopt módulo, que maneja opciones cortas y largas, incluida la evaluación de los valores de los parámetros.

La módulo argparse, que se deriva de la optparse módulo (disponible hasta Python 2.7).

La docopt módulo, que es disponible en GitHub, también permite la misma funcionalidad.

Recientemente, la absl La biblioteca también ha ido ganando fuerza, como medio para reemplazar optparse y getopt().

Cada una de estas formas tiene sus pros y sus contras, por lo que vale la pena evaluar cada una para ver cuál se adapta mejor a sus necesidades.

El módulo del sistema

Este es un módulo básico que se incluye con Python desde los primeros días. Se necesita un enfoque muy similar a la biblioteca C usando argc/argv para acceder a los argumentos. El módulo sys implementa los argumentos de la línea de comando en una estructura de lista simple llamada sys.argv.

Cada elemento de la lista representa un único argumento. El primer elemento de la lista, sys.argv[0], es el nombre del script Python. El resto de los elementos de la lista, sys.argv[1] a sys.argv[n], son los argumentos de la línea de comando 2 a n.

Como delimitador entre los argumentos se utiliza un espacio. Los valores de argumento que contienen un espacio deben estar entre comillas para poder ser analizados correctamente por sys.

El equivalente de argc es solo el número de elementos en la lista. Para obtener este valor, use Python len() operador. Mostraremos esto en un ejemplo de código más adelante.

Impresión del primer argumento de la CLI

En este primer ejemplo, nuestro script determinará la forma en que se llamó. Esta información se guarda en el primer argumento de la línea de comando, indexado con 0. El siguiente código muestra cómo se obtiene el nombre de su secuencia de comandos Python:

import sys

print("The script has the name %s" % (sys.argv[0])

Guarde este código en un archivo llamado arguments-program-name.pyy luego llámelo como se muestra a continuación. El resultado es el siguiente y contiene el nombre del archivo, incluida su ruta completa:

$ python arguments-program-name.py
The script has the name arguments-program-name.py
$ python /home/user/arguments-program-name.py
The script has the name /home/user/arguments-program-name.py

Como puede ver en la segunda llamada anterior, no solo obtenemos el nombre del archivo Python, sino también la ruta completa utilizada para llamarlo.

Contando el número de argumentos

En este segundo ejemplo simplemente contamos el número de argumentos de la línea de comando usando el comando incorporado len() método. sys.argv es la lista que tenemos que examinar. En el código siguiente, obtenemos el número de argumentos y luego restamos 1 porque uno de esos argumentos (es decir, el primero) siempre se establece como el nombre del archivo, lo que no siempre nos resulta útil. Por lo tanto, el número real de argumentos pasados ​​por el usuario es len(sys.argv) - 1:

import sys


arguments = len(sys.argv) - 1
print ("The script is called with %i arguments" % (arguments))

Guarde y asigne un nombre a este archivo arguments-count.py. A continuación se muestran algunos ejemplos de cómo llamar a este script. Esto incluye tres escenarios diferentes:

  • Una llamada sin más argumentos de línea de comando
  • Una llamada con dos argumentos
  • Una llamada con dos argumentos, donde el segundo es una cadena entre comillas que contiene un espacio
$ python arguments-count.py
The script is called with 0 arguments
$ python arguments-count.py --help me
The script is called with 2 arguments
$ python arguments-count.py --option "long string"
The script is called with 2 arguments
Iterando a través de argumentos

Nuestro tercer ejemplo genera todos los argumentos enviados al script de Python, excepto el nombre del programa en sí. Por lo tanto, recorremos los argumentos de la línea de comando comenzando con segundo elemento de lista. Recuerde que este es el índice 1 ya que las listas están basadas en 0 en Python:

import sys


arguments = len(sys.argv) - 1


position = 1
while (arguments >= position):
    print ("Parameter %i: %s" % (position, sys.argv[position]))
    position = position + 1

A continuación llamamos a nuestro código, que se guardó en el archivo arguments-output.py. Como se hizo en nuestro ejemplo anterior, el resultado ilustra tres llamadas diferentes:

  • Una llamada sin argumentos
  • Una llamada con dos argumentos
  • Una llamada con dos argumentos, donde el segundo argumento es una cadena entre comillas que contiene un espacio
$ python arguments-output.py
$ python arguments-output.py --help me
Parameter 1: --help
Parameter 2: me
$ python arguments-output.py --option "long string"
Parameter 1: --option
Parameter 2: long string

Recuerde, el objetivo de mostrar el ejemplo de cadena entre comillas es que los parámetros generalmente están delimitados por un espacio, a menos que están rodeados de comillas.

Banderas de rappel (absl)

La biblioteca Flags de Abseil está destinada a llevar los argumentos de la línea de comando a producción, con argumentos de línea de comando distribuidos. Cuando un módulo usa indicadores de línea de comandos y se importa a otro módulo, el otro módulo importa las banderas tambiény puede procesarlos reenviándolos al módulo importado.

Esto hace que los argumentos complejos de la línea de comandos compartidos entre módulos sean más fáciles y menos detallados.

Además, la biblioteca le permite definir los valores predeterminados, las descripciones y el tipo de datos de los argumentos, por lo que no son necesarias comprobaciones ni conversiones adicionales.

from absl import flags
import sys


flags.DEFINE_string('name', 'User', 'The name of the user.')


FLAGS = flags.FLAGS
FLAGS(sys.argv)

print(f"Hello {FLAGS.name}!")

Los tipos de datos admitidos son:

  • DEFINE_integer()
  • DEFINE_string()
  • DEFINE_bool()
  • DEFINE_enum()
  • DEFINE_list()
  • DEFINE_float()

Tanto como DEFINE_multi_integer(), DEFINE_multi_string() y DEFINE_multi_enum() para entrada de múltiples argumentos. Además, ejecutando --help, --helpfull, etc. imprimir las banderas existentes y sus descripciones, en diferentes formatos.

Consulte nuestra guía práctica y práctica para aprender Git, con las mejores prácticas, los estándares aceptados por la industria y la hoja de trucos incluida. Deja de buscar en Google los comandos de Git y, de hecho, aprenden ella!

La biblioteca también le permite definir validaciones, tanto en términos de rango, como valores basados ​​en números enteros que tienen un upper_bound or lower_bound eso es aceptable y ejecutar métodos arbitrarios para verificar los valores:

def validate_name(value):
    return len(value) > 15

flags.register_validator('name',
                         validate_name,
                         message='Name is over 15 characters long.',
                         flag_values=FLAGS)

Reuniéndolos en un ejemplo concreto:

from absl import flags
import sys

flags.DEFINE_string('name', 'User', 'The name of the user.')
flags.DEFINE_integer('tasks', 0, 'The number of tasks a user has.', lower_bound=0)

FLAGS = flags.FLAGS
FLAGS(sys.argv)

print(f"{FLAGS.name} has {FLAGS.tasks} tasks to work on.")
$ python flags.py --name=John --tasks=5
John has 5 tasks to work on.
$ python flags.py --name=John --tasks=-1

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_flag.py", line 180, in _parse
    return self.parser.parse(argument)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_argument_parser.py", line 168, in parse
    raise ValueError('%s is not %s' % (val, self.syntactic_help))
ValueError: -1 is not a non-negative integer
...

El módulo argparse

La módulo argparse ha estado disponible desde Python 3.2, y una mejora del optparse módulo que existe hasta Python 2.7. La documentación de Python contiene una descripción de la API y un tutorial que cubre todos los métodos en detalle.

El módulo ofrece una interfaz de línea de comandos con una salida estandarizada, mientras que las dos soluciones anteriores dejan gran parte del trabajo en sus manos. argparse permite la verificación de argumentos fijos y opcionales, con verificación de nombres en estilo corto o largo. Como argumento opcional predeterminado, incluye -h, junto con su versión larga --help. Este argumento va acompañado de un mensaje de ayuda predeterminado que describe los argumentos aceptados.

El siguiente código muestra la inicialización del analizador y el resultado siguiente muestra la llamada básica, seguida del mensaje de ayuda. A diferencia de las llamadas a Python que usamos en los ejemplos anteriores, recuerde usar Python 3 con estos ejemplos:


import argparse


parser = argparse.ArgumentParser()
parser.parse_args()
$ python3 arguments-argparse-basic.py 
$ python3 arguments-argparse-basic.py -h
usage: arguments-argparse-basic.py [-h]

optional arguments:
  -h, --help  show this help message and exit
$ python3 arguments-argparse-basic.py --verbose
usage: arguments-argparse-basic.py [-h]
arguments-argparse-basic.py: error: unrecognized arguments: --verbose

En el siguiente paso, agregaremos una descripción personalizada al mensaje de ayuda para nuestros usuarios. Inicializar el analizador de esta manera permite un texto adicional. El siguiente código almacena la descripción en el text variable, que se da explícitamente a la argparse clase como el description parámetro. Al llamar a este código a continuación, puede ver cómo se ve el resultado:


import argparse


text = 'This is a test program. It demonstrates how to use the argparse module with a program description.'


parser = argparse.ArgumentParser(description=text)
parser.parse_args()
$ python3 arguments-argparse-description.py --help
usage: arguments-argparse-description.py [-h]

This is a test program. It demonstrates how to use the argparse module with a
program description.

optional arguments:
  -h, --help  show this help message and exit

Como paso final agregaremos un argumento opcional llamado -V, que tiene un argumento de estilo largo correspondiente llamado --version. Para ello utilizamos el método add_argument() que llamamos con tres parámetros (que se muestran para --version, solo):

  • El nombre del parámetro: --version
  • El texto de ayuda para el parámetro: help="show program version"
  • Acción (sin valor adicional): action="store_true"

El código fuente para esto se muestra a continuación. Leer los argumentos en la variable llamada args se realiza a través del parse_args() método del parser objeto. Tenga en cuenta que envía tanto la versión corta como la larga en una sola llamada. Finalmente, verificas si los atributos args.V or args.version están configurados y generan el mensaje de versión:


import argparse


parser = argparse.ArgumentParser()
parser.add_argument("-V", "--version", help="show program version", action="store_true")


args = parser.parse_args()


if args.version:
    print("This is myprogram version 0.1")
$ python3 arguments-argparse-optional.py -V
This is myprogram version 0.1
$ python3 arguments-argparse-optional.py --version
This is myprogram version 0.1

La --version El argumento no requiere que se proporcione un valor en la línea de comando. Es por eso que configuramos el argumento de acción en "store_true". En otros casos, es posible que necesite un valor asignado adicional, por ejemplo, si especifica un determinado volumen, alto o ancho. Esto se muestra en el siguiente ejemplo. Como caso predeterminado, tenga en cuenta que todos los argumentos se interpretan como cadenas:


import argparse


parser = argparse.ArgumentParser()


parser.add_argument("--width", "-w", help="set output width")


args = parser.parse_args()


if args.width:
    print("Set output width to %s" % args.width)

Aquí mostramos lo que sucede al enviar diferentes valores de argumento. Esto incluye tanto la versión corta como la larga, así como el mensaje de ayuda:

$ python3 arguments-argparse-optional2.py -w 10
Set output width to 10
$ python3 arguments-argparse-optional2.py --width 10
Set output width to 10
$ python3 arguments-argparse-optional2.py -h
usage: arguments-argparse-optional2.py [-h] [--width WIDTH]

optional arguments:
  -h, --help            show this help message and exit
  --width WIDTH, -w WIDTH
                        set output width

El módulo getopt

Como habrás notado antes, el sys El módulo divide la cadena de la línea de comando en facetas individuales únicamente. La pitón módulo getopt va un poco más allá y amplía la separación de la cadena de entrada mediante la validación de parámetros. Basado en el getopt Función C, permite opciones tanto cortas como largas, incluida una asignación de valor.

En la práctica, requiere la sys módulo para procesar los datos de entrada correctamente. Para ello, tanto el sys módulo y el getopt El módulo debe cargarse de antemano. A continuación, de la lista de parámetros de entrada eliminamos el primer elemento de la lista (consulte el código a continuación) y almacenamos la lista restante de argumentos de la línea de comando en la variable llamada argument_list:


import getopt, sys


full_cmd_arguments = sys.argv


argument_list = full_cmd_arguments[1:]

print argument_list

Los argumentos en argument_list ahora se puede analizar usando el getopts() método. Pero antes de hacer eso, debemos decirle getopts() sobre qué parámetros son válidos. Se definen así:

short_options = "ho:v"
long_options = ["help", "output=", "verbose"]

Esto significa que estos argumentos son los que consideramos válidos, junto con información adicional:

------------------------------------------
long argument   short argument  with value
------------------------------------------
--help           -h              no
--output         -o              yes
--verbose        -v              no
------------------------------------------

Es posible que haya notado que el o la opción corta fue precedida por dos puntos, :. Esto le dice a getopt que a esta opción se le debe asignar un valor.

Esto ahora nos permite procesar una lista de argumentos. El getopt() El método requiere la configuración de tres parámetros: la lista de argumentos reales de argv, así como las opciones corta y larga válidas (que se muestran en el fragmento de código anterior).

La llamada al método en sí se mantiene en una declaración try-catch para cubrir errores durante la evaluación. Se genera una excepción si se descubre un argumento que no forma parte de la lista definida anteriormente. El script de Python imprimirá el mensaje de error en la pantalla y saldrá con el código de error 2:

try:
    arguments, values = getopt.getopt(argument_list, short_options, long_options)
except getopt.error as err:
    
    print (str(err))
    sys.exit(2)

Finalmente, los argumentos con los valores correspondientes se almacenan en las dos variables denominadas arguments y values. Ahora puedes evaluar fácilmente estas variables en tu código. Podemos usar un for-bucle para recorrer la lista de argumentos reconocidos, una entrada tras otra.


for current_argument, current_value in arguments:
    if current_argument in ("-v", "--verbose"):
        print ("Enabling verbose mode")
    elif current_argument in ("-h", "--help"):
        print ("Displaying help")
    elif current_argument in ("-o", "--output"):
        print (("Enabling special output mode (%s)") % (current_value))

A continuación puede ver el resultado de la ejecución de este código. Mostraremos cómo reacciona el programa con argumentos de programa válidos e inválidos:

$ python arguments-getopt.py -h
Displaying help
$ python arguments-getopt.py --help
Displaying help
$ python arguments-getopt.py --output=green --help -v
Enabling special output mode (green)
Displaying help
Enabling verbose mode
$ python arguments-getopt.py -verbose
option -e not recognized

La última llamada a nuestro programa puede parecer un poco confusa al principio. Para entenderlo, debes saber que las opciones abreviadas (a veces también llamadas banderas) se pueden usar juntas con un solo guión. Esto permite que su herramienta acepte más fácilmente muchas opciones. Por ejemplo, llamando python arguments-getopt.py -vh es lo mismo que llamar python arguments-getopt.py -v -h. Entonces, en la última llamada anterior, el getopt El módulo pensó que el usuario estaba intentando pasar. -e como opción, lo cual no es válido.

Conclusión

En este artículo mostramos muchos métodos diferentes para recuperar argumentos de línea de comando en Python, incluido el uso sys, getopty argparse. Estos módulos varían en funcionalidad, algunos proporcionan mucho más que otros. sys es totalmente flexible, mientras que ambos getopty argparse requieren cierta estructura. Por el contrario, cubren la mayor parte del trabajo complejo que sys te deja a ti. Después de trabajar con los ejemplos proporcionados, debería poder determinar qué módulo se adapta mejor a su proyecto.

En este artículo no hablamos de otras soluciones como la docopts módulo, lo acabamos de mencionar. Este módulo sigue un enfoque totalmente diferente y se explicará en detalle en uno de los próximos artículos.

Referencias

Sello de tiempo:

Mas de Abuso de pila