Línea de comandos en Python

En este artículo vamos a seguir aprendiendo Python convirtiendo, poco a poco, nuestros programas en cosas más y más útiles.

En este caso vamos a mejorar la forma en la que nuestro programa paridad.py puede comunicarse con el sistema operativo recibiendo información a través de la línea de comandos, en lugar de utilizar simplemente la entrada estándar.

La línea de comandos es un mecanismo que el shell dispone para poder parametrizar la ejecución de los programas, introduciendo no sólo datos de entrada, sino también parámetros de comportamiento. En nuestros lenguajes de programación, esto se traduce en una librería estándar que proporciona tanto estructuras de datos, conteniendo los parámetros y argumentos del programa, como funciones para manipularlos, si ello fuese necesario.

La forma de utilizar la línea de comandos para introducir parámetros y argumentos es, simplemente, escribir todos los parámetros y argumentos después del nombre del programa a ejecutar, separados por espacios. Fíjate en la siguiente herramienta, ls, y cómo su comportamiento cambia al introducir una serie de parámetros y argumentos:

$ ls 
Applications Developer    Downloads    Movies       Pictures     Public
Desktop      Documents    Library      Music        Postman      opt

$ ls -lh
total 0
drwx------@  8 gabriel  gabriel   256B 23 Feb 15:03 Applications
drwx------@ 11 gabriel  gabriel   352B 13 Mar 16:20 Desktop
drwx------  18 gabriel  gabriel   576B  7 Mar 15:47 Developer
drwx------@ 10 gabriel  gabriel   320B  9 Feb 10:51 Documents
drwx------@ 47 gabriel  gabriel   1.5K 13 Mar 15:08 Downloads
drwx------+ 96 gabriel  gabriel   3.0K 10 Mar 19:39 Library
drwx------   4 gabriel  gabriel   128B 30 Jan 14:03 Movies
drwx------+  4 gabriel  gabriel   128B 27 Jan 15:51 Music
drwx------+  8 gabriel  gabriel   256B 16 Feb 09:38 Pictures
drwxr-xr-x   3 gabriel  gabriel    96B 22 Feb 14:57 Postman
drwxr-xr-x+  4 gabriel  gabriel   128B 23 Dec 09:02 Public
drwxr-xr-x   9 gabriel  gabriel   288B 22 Feb 14:47 opt

$ ls -lh Desktop                                     
total 48
-rw-r--r--@ 1 gabriel  gabriel    22K 17 Feb 16:45 learnthispower.png

En el primer ejemplo, ls (list files) presenta el nombre de los ficheros o directorios presentes en el directorio actual.

Al introducir el parámetro -lh, que en realidad son dos, -l -h, pero en una forma contracta, el programa cambia el formato de la salida y presenta mucha más información:

Por último, si además (o en lugar de) parámetros de funcionamiento, terminamos la línea de comandos con un nombre de directorio o fichero existente como argumento, ls se centrará en el mismo. En el caso de directorios, mostrará el contenido de dicho directorio.

Veamos la versión original de paridad.py, omitiendo ya los comentarios explicativos:

#!/usr/bin/python3              

import sys

num = int( input() )   

if num % 2 == 0 :       
    print("par")
else :                  
    print ("impar") 

Por si no lo recuerdas, este programa acepta un número entero por la entrada estándar, ya sea de forma interactiva o utilizando el pipe, y escribe par o impar en la salida estándar.

Vamos a modificar el programa de acuerdo para que acepte el número a examinar como argumento, con el siguiente objetivo:

Para ello, vamos a usar una estructura de datos proporcionada por la librería sys, que es sys.argv. En esta estructura de datos, de tipo array, o formación, tenemos lo siguiente:

Prueba este programa:

#!/usr/bin/python3              

import sys

for op in sys.argv:
    print(op);

Si guardas ese código en un fichero, por ejemplo argv.py y lo ejecutas este programa tras otorgarle permisos de ejecución con chmod +x argv.py, verás lo siguiente:

$ ./argv.py
./argv.py
$ ./argv.py hola mundo
./argv.py
hola
mundo

Lo que hace el código es ejecutar un bucle for sobre sys.argv. El bucle for se lee, literalmente: para cada elemento, op, en sys.argv: imprime el valor de op.

Así pues, una solución a nuestro programa es la siguiente:

#!/usr/bin/python3              

import sys

if len(sys.argv) > 1 :
    num = int(sys.argv[1])
else:
    num = int(input())   

if num % 2 == 0 :       
    print("par")
else :                  
    print ("impar") 

Lo que hace el código que hemos añadido es:

Vamos a probarlo para comprobar, no sólo que hemos resuelto el problema, sino que, además, no hemos roto nada:

$ ./paridad.py 
45
impar
$ echo 4 | ./paridad.py
par
$ ./paridad.py 23
impar

Como nota final, el hecho de no romper nada al cambiar un programa, esto es, conservar su funcionamiento original a través de distintas actualizaciones a lo largo de su vida útil, es una cualidad llamada compatibilidad hacia atrás.

Es una traducción tosca del inglés backwards compatibility, pero nos podemos hacer una idea de lo importante que es si, con el paso del tiempo, nuestros usuarios han construido muchos pipelines usando paridad.py.

👉 Sigue a micromáquina en @gabriel@micromaquina.com 👉 Sigue a Gabriel Viso en @gabriel@fedi.gvisoc.com