Cómo analizar argumentos de línea de comandos en Python

¿Quiere ejecutar secuencias de comandos de Python con argumentos de línea de comandos? Aprenda a analizar argumentos de la línea de comandos con los módulos sys, getopt y argparse en Python.

En Python, cuando desee leer la entrada del usuario, utilizará la función input(). Sin embargo, para algunas aplicaciones, es posible que desee pasar ciertos argumentos mientras ejecuta el script en la línea de comando.

En este tutorial, aprenderemos a ejecutar un script de Python con opciones y argumentos en la línea de comandos. Luego aprenderemos a usar los módulos integrados de Python para analizar dichas opciones y argumentos.

¡Vamos a empezar!

Entendiendo sys.argv en Python

Si ha programado en C, sabe que una de las formas más sencillas de pasar argumentos al programa es a través de la línea de comandos. Para hacerlo, puede estructurar la función principal de la siguiente manera:

#include<stdio.h>

int main(int argc, char **argv){
    //argc: argument count
    //argv: argument vector
    
    //do something on the args

    return 0;
}

Aquí, argc representa el conteo de argumentos y argv representa el vector de argumentos.

Ejecución de secuencias de comandos de Python con argumentos de línea de comandos

En Python, puede ejecutar el script de Python en la línea de comando usando python3 filename.py. Al hacerlo, también puede pasar un número arbitrario de argumentos de línea de comandos:

$ python3 filename.py arg1 arg2 ... argn

El módulo sys proporciona soporte listo para usar para acceder y procesar estos argumentos de la línea de comandos. sys.argv es la lista de todos los argumentos de la línea de comandos que pasamos cuando ejecutamos el script de Python.

Aquí hay un ejemplo en el que ejecutamos main.py con argumentos de línea de comandos:

$ python3 main.py hello world python script

Podemos recorrer el vector de argumento usando una simple función de bucle y enumeración:

# main.py

import sys

for idx, arg in enumerate(sys.argv):
    print(f"arg{idx}: {arg}")
# Output
arg0:main.py
arg1:hello
arg2:world
arg3:python
arg4:script

Vemos que el primer argumento (en el índice 0) es el nombre del archivo Python. Y los argumentos posteriores comienzan en el índice 1.

Este es un programa de trabajo mínimo que acepta y procesa argumentos de línea de comandos. Sin embargo, vemos algunos problemas:

  • ¿Cómo saben los usuarios del programa qué argumentos pasar?
  • ¿Y qué significan estos argumentos?

Esto no está muy claro. Para abordar esto, puede usar los módulos getopt o argparse. Y eso lo aprenderemos en las próximas secciones.✅

Análisis de argumentos de línea de comandos usando getopt de Python

Aprendamos a analizar argumentos de la línea de comandos usando el módulo getopt integrado.

Después de importar getopt desde el módulo getopt, puede especificar los argumentos para analizar y las opciones cortas y largas para ejecutar el script. Necesitamos analizar todos los argumentos que comienzan en el índice 1 en sys.argv. Entonces, el segmento para analizar es sys.argv[1:].

Aquí, necesitaremos una cadena de mensaje y un nombre de archivo. Usemos m y f como opciones cortas y mensaje y archivo como opciones largas.

Pero, ¿cómo nos aseguramos de que una opción específica requiera un argumento?

  • En las opciones cortas, puede hacer que una opción requiera un argumento agregando dos puntos (:) después del nombre de la opción corta.
  • De manera similar, en las opciones largas, puede agregar un signo = después de la opción larga. Podemos capturar estas opciones y sus respectivos argumentos.

Al agregarlos, tendremos el siguiente código en main.py:

# main.py

import sys
from getopt import getopt

opts, args = getopt(sys.argv[1:],'m:f:',['message=","file="])

print(opts)
print(args)

Aquí, la variable opts contiene las opciones y los argumentos como una lista de tuplas. Cualquier otro argumento posicional que pasemos se recopilará en la variable args.

Podemos pasar el mensaje y el nombre del archivo para ejecutar el script, y podemos usar las opciones cortas o largas.

Ejecutando main.py usando las opciones largas, tenemos:

$ python3 main.py --message hello --file somefile.txt

Tenemos las opciones y argumentos como tuplas en la variable opts. Como no hemos pasado ningún argumento posicional, args es una lista vacía.

# Output
[("--message', 'hello'), ('--file', 'somefile.txt')]
[]

De manera equivalente, también podemos usar las opciones cortas como se muestra:

$ python3 main.py -m hello -f somefile.txt
# Output
[('-m', 'hello'), ('-f', 'somefile.txt')]
[]

⚠️ La opción abreviada -m en este ejemplo no debe confundirse con el indicador de línea de comando -m que se usa para ejecutar un módulo como módulo principal cuando se ejecuta una secuencia de comandos de Python.

Por ejemplo, usará python3 -m unittest main.py para ejecutar unittest como el módulo principal cuando ejecute main.py.

Mencionamos que todos los demás argumentos posicionales que pasemos se recopilarán en la variable args. Aquí hay un ejemplo:

$ python3 main.py -m hello -f somefile.txt another_argument

La lista de argumentos contiene el argumento posicional otro_argumento.

# Output
[('-m', 'hello'), ('-f', 'somefile.txt')]
['another_argument']

Aquí, opts es una lista de tuplas. Entonces podemos recorrerlo, desempaquetar la tupla y extraer los argumentos correspondientes a las opciones específicas.

Pero, ¿qué hacemos con el nombre del archivo y el mensaje después de haber procesado estos argumentos? Abriremos el archivo en el modo de escritura y escribiremos la cadena del mensaje convertida a mayúsculas en el archivo.

# main.py
import sys
from getopt import getopt

opts, args = getopt(sys.argv[1:],'m:f:',['message=","file="])

print(opts)
print(args)

for option, argument in opts:
    if option == "-m':
        message = argument
    if option == '-f':
        file = argument

with open(file,'w') as f:
    f.write(message.upper())

Ejecutemos main.py con las opciones cortas y los argumentos de la línea de comandos.

$ python main.py -m hello -f thisfile.txt
[('-m', 'hello'), ('-f', 'thisfile.txt')]
[]

Después de ejecutar main.py, podemos ver ‘thisfile.txt’ en nuestro directorio de trabajo. Contiene la cadena ‘hola’ convertida a mayúsculas (‘HOLA’).

$ ls
main.py  thisfile.txt
$ cat thisfile.txt
HELLO

Cómo analizar argumentos de línea de comandos con Argparse

El módulo argparse, también integrado en la biblioteca estándar de Python, proporciona funcionalidad para analizar argumentos de línea de comandos y también para crear interfaces de línea de comandos.

Para analizar los argumentos de la línea de comandos, importemos la clase ArgumentParser del módulo argparse. Aquí, hemos instanciado arg_parser, un objeto ArgumentParser:

from argparse import ArgumentParser

arg_parser = ArgumentParser()

A continuación, nos gustaría agregar dos argumentos de línea de comandos:

  • mensaje: la cadena del mensaje, y
  • archivo: el nombre del archivo con el que nos gustaría trabajar.

Ahora llamamos al método add_argument() en arg_parser para agregar estos dos argumentos. En la llamada al método add_argument(), puede establecer ayuda en una cadena (una descripción del argumento).

arg_parser.add_argument('message',help='message string')
arg_parser.add_argument('file',help='filename')

Hasta ahora, hemos instanciado arg_parser y agregado los argumentos de la línea de comandos. Cuando el programa se ejecuta en la línea de comando, puede usar el método parse_args() en arg_parser para obtener los valores de los argumentos.

Aquí, capturamos el espacio de nombres del argumento en la variable args. Entonces puede usar args.argument_name para obtener los valores de los argumentos.

Después de obtener los valores de los argumentos, escribimos la cadena del mensaje con mayúsculas y minúsculas (utilizando el método de cadena swapcase()) en el archivo.

args = arg_parser.parse_args()

message = args.message
file = args.file

with open(file,'w') as f:
     f.write(message.swapcase())

Poniéndolo todo junto, aquí está nuestro archivo main.py:

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('message',help='message string')
arg_parser.add_argument('file',help='filename')

args = arg_parser.parse_args()
print(args)

message = args.message
file = args.file

with open(file,'w') as f:
     f.write(message.swapcase())

Comprensión del uso de argumentos de línea de comandos

Para comprender el uso de los argumentos al ejecutar main.py, puede usar la opción –help long como se muestra:

$ python3 main.py --help
usage: main.py [-h] message file

positional arguments:
  message     message string
  file        filename

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

No hay argumentos opcionales y tanto el mensaje como el archivo son argumentos posicionales obligatorios. Alternativamente, también puede usar la opción corta -h:

$ python3 main.py -h
usage: main.py [-h] message file

positional arguments:
  message     message string
  file        filename

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

Como se ve, ambos argumentos son argumentos posicionales por defecto. Entonces, si no pasa uno o más de estos argumentos, se encontrará con errores.

Aquí, hemos pasado un argumento posicional (Hola) para la cadena del mensaje, pero no hemos proporcionado ningún valor para el argumento del archivo.

Y recibimos un error que indica que se requiere el argumento del archivo.

$ python3 main.py Hello
usage: main.py [-h] message file
main.py: error: the following arguments are required: file

Cuando ejecutamos main.py con ambos argumentos posicionales, vemos que el espacio de nombres args contiene los valores de los argumentos.

$ python3 main.py Hello file1.txt
# Output
Namespace(file="file1.txt", message="Hello")

Ahora, si examinamos el contenido del directorio de trabajo actual, vemos que el script crea el archivo ‘file1.txt’:

$ ls
file1.txt  main.py

La cadena del mensaje original es ‘Hola’; después de cambiar el caso, la cadena de mensaje en el archivo ‘file1.txt’ es ‘hELLO’.

$ cat file1.txt
hELLO

Cómo hacer que los argumentos de la línea de comandos sean opcionales

Para hacer que estos argumentos de la línea de comandos sean opcionales, puede anteponer el nombre del argumento con –.

Modifiquemos main.py para que tanto el mensaje como los argumentos del archivo sean opcionales.

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('--message',help='message string')
arg_parser.add_argument('--file',help='filename')

Como los argumentos de la línea de comandos son opcionales, podemos establecer valores predeterminados para estos argumentos.

if args.message and args.file:
    message = args.message
    file = args.file
else:
    message="Python3"
    file="myfile.txt"

En este punto, el archivo main.py contiene el siguiente código:

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('--message',help='message string')
arg_parser.add_argument('--file',help='filename')

args = arg_parser.parse_args()
print(args)

if args.message and args.file:
    message = args.message
    file = args.file
else:
    message="Python3"
    file="myfile.txt"

with open(file,'w') as f:
     f.write(message.swapcase())

Si verificamos el uso, vemos que tanto el mensaje como el archivo son argumentos opcionales. Lo que significa que ahora puede ejecutar main.py sin estos dos argumentos.

$ python3 main.py --help
usage: main.py [-h] [--message MESSAGE] [--file FILE]

optional arguments:
  -h, --help         show this help message and exit
  --message MESSAGE  message string
  --file FILE        filename
$ python3 main.py

En el espacio de nombres del argumento, tanto el archivo como el mensaje son Ninguno.

# Output
Namespace(file=None, message=None)

Vemos que se utilizan el nombre de archivo predeterminado y el mensaje ‘myfile.txt’ y ‘Python3’. El archivo ‘myfile.txt’ ahora está en el directorio de trabajo:

$ ls
file1.txt  main.py  myfile.txt

Y contiene la cadena ‘Python3’ con el caso de las letras intercambiadas:

$ cat myfile.txt
pYTHON3

También puede usar los argumentos –message y –file para hacer que el comando sea más legible.

$ python3 main.py --message Coding --file file2.txt
# Output
Namespace(file="file2.txt", message="Coding")

Vemos el ‘file2.txt’ en el directorio de trabajo:

$ ls
file1.txt  file2.txt  main.py  myfile.txt

Y contiene la cadena ‘CODING’ como se esperaba.

$ cat file2.txt
cODING

Conclusión

Aquí hay un resumen de lo que hemos aprendido en este tutorial:

  • Al igual que en el lenguaje de programación C, en Python, puede acceder a los argumentos de la línea de comandos recorriendo el vector de argumento sys.argv. sys.argv[0] es el nombre del script de Python. Entonces estamos interesados ​​en analizar los argumentos sys.argv[1:].
  • Sin embargo, para mejorar la legibilidad y poder agregar opciones, puede utilizar los módulos getopt y argparse.
  • Puede utilizar el módulo getopt para analizar la lista de argumentos de la línea de comandos desde el índice 1 hasta el final de la lista. Puede especificar tanto opciones cortas como opciones largas.
  • Cuando una opción toma un argumento, puede especificar dos puntos (:) y = después de la opción corta y la opción larga, respectivamente.
  • Con el módulo argparse de Python, puede crear una instancia de un objeto ArgumentParser y usar el método add_argument() para agregar un argumento posicional requerido. Utilice — antes del nombre del argumento para que sea opcional.
  • Para recuperar los valores de los argumentos de la línea de comandos, llame al método parse_args() en el objeto ArgumentParser.

A continuación, aprenda cómo realizar hash seguro en Python.