viernes, 2 de marzo de 2018

Scripting con Zenity... para newbies (I)

Estoy seguro de que esta entrada del Blog va a producir grandes carcajadas entre los gurús de informática que la lean, por ejemplo a mi amigo ‘neurus’ de EspacioLinux.com, que tanto me ayuda, y del que se que, a veces, visita este Blog. Y es que voy a asomar las narices por el terreno de crear ‘programillas’ (bueno, pequeños scripts) usando Zenity, que es un divertido invento, ya algo viejo, que no conocía, y en cuya pista me puso el propio neurus.
Mi única intención es tratar de ‘digerir’ algunos conceptos útiles, y explicarlos ‘a mi manera’ (o sea, a la manera de un novato, como he hecho siempre), para que me sirvan como ‘Apuntes tácticos’. Así que sigo basándome en la ‘Regla de los 5 minutos’, y, quien lea esto, que no ‘rasque’ mucho en ello, preguntándome cosas, que mi conocimiento es muy superficial. Pero es que todo lo que he leido sobre Zenity en Blogs amigos (que Google ofrece bastante información) me ha parecido que es para gente más lista que yo, y quiero aclarar conceptos… ‘para no morir en el intento’.Así que vamos allá...

Pero antes de nada, voy a apuntarme aquí algunos conceptos básicos de Bash… más que nada para ‘culturizarme’ un poco.
Y empiezo con una nota que, realmente, solo tiene un valor cultural. El shell Bash es el intérprete de comandos estándar que linux utiliza ‘por defecto’. ‘Shell’ es como se llama, genéricamente, al programa que interpreta las órdenes tecleadas en la terminal y las traduce a instrucciones internas del sistema. No está incluido en el núcleo del sistema, y por eso se le llamó shell (caparazón). Y Bash viene de ‘Bourne Again SHell’, un juego de palabras, en honor de Stephen Bourne que fue el creador del primer ‘shell’ de Unix porque, efectivamente, es un nuevo shell ‘de tipo Bourne’, de características avanzadas (incluye algunas de los ‘shells tipo C’). Y a este interprete de comandos que, como dije, ha adoptado Linux, se le invoca (por ejemplo, para mandar ejecutar un script) o bien con la orden inicial ‘sh’ o bien con la orden ‘bash’.

Y, ahora, hablemos de algunos conceptos básicos para el lenguaje en Bash:
Los comandos
Son las órdenes que introducimos por consola. En realidad todo lo que escribas en la consola para hacer algo es o una información (de texto), o un comando. Algunos son automáticamente reconocidos (exit, para salir, ls, para listar algo, el comando ‘echo’ (que hace que lo que se indique detrás de esta palabra aparezca en pantalla), etc, etc. (Hay muchísimos, este es el ‘mundo del programador’, así que… Google).
Pero también son comandos las ‘instrucciones (o mandatos) que introduces, como puede ser un script creado, un mandato condicional (if… then…), etc.

Las variables
La palabra 'variable' es muy común, en programación. Mi primer error, como principiante, fue que identificaba 'variable' con el concepto de 'dato que no es constante'. Y no, no tiene nada que ver (o 'no siempre es así'), es algo más simple, y más genérico:
'variable' solo quiere indicar ‘espacio que necesitamos para guardar un dato. 
Se identifica con una palabra (el nombre de la variable) que no puede contener caracteres especiales, espacios o empezar con números (para evitar confundirse con variables específicas, que los contienen). También, por algo parecido, se recomienda que se escriban en minúsculas. Pues vale.
Una variable se invoca, en general, con la expresión $nombre_variable.  
Y el dato que va a contener puede ser... 
a) introducido de manera directa, por teclearlo, o por leerlo directamente el propio intérprete, mediante el comando ‘read’, con esta sintaxis: (por ejemplo)
read -p "introduce (copia y pega) la dirección web de un video: " video
que nos introduce, como variable de nombre ‘video’, lo que hayamos copiado y pegado (y que con escribir $video, lo invocamos).
NOTA: aquí, el modificador -p hace que se muestre el ‘prompt’, sin un salto de línea al final, antes de intentar leer nada de la entrada, lo que facilita la introducción del dato a leer.
b) Introducido por recibir el resultado de un comando
La sintaxis es, en este caso, nombre_variable=(comando). El texto del comando se debe colocar entre paréntesis, o entre `comillas invertidas` (en realidad `acentos invertidos`).  
Es decir, lo que estamos indicando es que se ejecute el comando, y que lo que resulte de su ejecución se llame ‘nombre_variable’. De esta manera nos será muy sencillo invocarlo desde otra instancia, o sea hacer que la salida de un comando sea el argumento de entrada del siguiente, sin más que escribir $nombre_variable
Y ese comando (la instrucción) que mandamos ejecutar puede ser sencillo, incluso predeterminado, como por ejemplo
fecha=(date +%Y%m%d)
que presentará en consola la fecha del día invocando la variable con un simple ‘echo $fecha
… o complejo si el comando es largo, o con varias instrucciones encadenadas. 
En este caso es muy frecuente que se escriba distribuyéndolo en varias líneas. Y cada línea tiene que acabar con una antibarra ( \ ) para indicar continuidad. 
Dos ejemplos
blog=`/usr/bin/firefox http://comoserdebianitaynomorirenelintento.blogspot.com.es/`
nos abriría el firefox, y precisamente en este blog, con solo invocar la función $blog
Y aquí, un comando largo, escrito por líneas, para definir la variable 'dato'
dato=(zenity --list --width="300" --height="200" \
--title="Elige lo que deseas hacer" \
--column="Opción a elegir" "CREAR un nuevo script" "EJECUTAR uno ya creado") 
(por supuesto, si hay palabras separadas, hay que meterlas entre “comillas dobles”)
Así que (por terminar ya con las ‘variables’) queda claro que, en un script, al escribir, por ejemplo
youtube-dl -f $cod $video
estamos diciendo que el mandato youtube-dl -f emplee el dato (variable) que definamos, en cada caso, como $cod (se refiere, en el caso, al ‘código elegido del formato de video a descargar’) y el que definamos como $video (por ejemplo, ‘la dirección web de un determinado video seleccionado’)

Las funciones
El concepto de ‘función’ es un gran invento en programación: si tengo varios comandos, o sentencias, largos y repetitivos, los puedo definir como una función, dándole un nombre, y luego me bastaría invocar esa sola palabra para se me ejecuten todos los comandos o sentencias que recoge.
La sintaxis de una función es esta:
function nombre_función () {
comando o comandos a incluir
}
y las funciones pueden, incluso, complejas, incluir varias ordenes condicionales, etc. de manera que, siendo muy interesantes en programación, también lo pueden ser en ‘scripting’.
Y es importante decir que la función, que se la invoca escribiendo el nombre que le hayamos asignado (así de sencillo, de ahí que convenga vigilar que no haya coincidencias con términos comunes, y la liemos...) ‘se debe declarar’ antes de ser invocada, por lo que es muy recomendable escribirlas al principio del script o del programa.

Las órdenes condicionales
Esto, un concepto muy común en programación, es todo un mundo. Las órdenes más básicas son el if...then, el case...esac, el for…, el do...done, el while (y until)-do-done...que, si interesan, se pueden consultar por ejemplo aquí (o, simplemente, buscando por Google) porque solo voy a hablar de dos, muy clásicas:
la sentencia if… then con o sin else (‘de lo contrario’)
Muy sencillo… en enfoques sencillos. Su sintaxis es:
if [ condición ];
then ‘haz esto’
else ‘haz esto otro’
fi
La sentencia case
Case es otra función ‘condicional’, parecida a if, pero con un enfoque que puede ser más útil porque simplifica bastante la instrucción a crear, y además puede estar contenida dentro de otras estructuras con if… o con While.... Y por cierto, así como la sentencia if hay que terminarla con un ‘fi’, ‘case’ termina su sentencia con un ‘esac’.
Su sintaxis, si llamamos ‘expresión’ a lo que introduzcamos, generalmente el valor de una variable, es así: “case expresion in (que sería el planteamiento: 'si esta expresión (por ejemplo una variable) adopta el patrón...(o da como resultado...') y se añade ), 'este resultado obtenido', 'se ejecutará el comando...' ;;... etc. 
Se entiende muy bien viendo este ejemplo de orden condicional, con case:
case $DATO in
"CREAR un nuevo script")
comandoA
;;

"EJECUTAR uno ya creado")
comandoB
;;

(etc)
esac
(hay que tener mucho cuidado con poner bien el paréntesis, los dobles punto y coma, etc.)

Argumentos, tuberias, redireccionamientos y cosas variopintas
Acabo con un repasito a una cosa más: de una serie de signos que de ven en lo programas y scripts… más que nada para saber de qué va la cosa.
Por ejemplo veo $1, $2, $3… son como las variables, pero ¿1, 2, 3…? A ver si se explicarlo, se llaman ‘argumentos’ a los parámetros (posicionales) que necesita un script para, cuando es invocado, poder ejecutarse. Primer parámetro, segundo, tercero… Estos argumentos pueden ser invocados como variables $1, $2, $3… y los podemos tratar por separado, dando una gran flexibilidad a nuestros scripts ya que mediante ellos podemos indicar con qué dato queremos trabajar a continuación. 
Hay otras variables especiales, de este estilo: La variable $0 indica el nombre del fichero en ejecución, $? indica el valor devuelto por el ultimo comando, $* (y $@) indican (con distinto enfoque) todos los argumentos de la shell, $# el número de parámetros que contiene el script, etc, etc..
Aquí se cuentan cosas,
Pero vamos a cosas más claras: las tuberias y los redireccionamientos
el ‘punto y coma’ por ejemplo, A ; B… significa ‘haz B aunque A de error’
A && B significa ejecuta B cuando acabe bien A
A || B significa ejecuta B si falla A
A & significa ejecuta A en segundo plano
la barra vertical | es una tubería que dirige la salida estandar de una orden a la entrada de otra.
2>&1 significa ‘redirigir los errores a la salida normal’ 
(la explicación de este signo aclara bastantes conceptos: en primer lugar, el símbolo > significa ‘redirigir’ (por ejemplo,... echo ... > archivo.txt)
NOTA: El 1 es el descriptor que identifica la salida estandar (stdout) y el 2 el de la salida de errores (stderr), etc.. (El descriptor ‘ * ‘ sería ‘el resto’, y el 0 sería la entrada estandar). Por ejemplo, aquí se explica todo de forma muy sencilla. Si queremos redirigir los errores a la salida normal (stdout), para evitar que 2>1 signifique que la salida de errores se convierta en ‘el archivo 1’, se pone ‘&1’, que indica que es ‘el descriptor de la salida normal’

Y ya vale. En menudo lío me he metido, esto de programar es dificilísimo, y requiere estudiarlo en profundidad. Bueno, sin duda es una asignatura, incluso una carrera, así que me parece que todo lo que pongo aquí es una castaña. El abecedario, vamos.
Pero bueno, espero que esta entrada sirva solo para saber interpretar algunos conceptos.Vamos, para estar a un nivel como, por ejemplo, el mío de inglés: que no se hablar, pero si me ponen un libro de instrucciones en inglés… a lo mejor me entero de algo.

1 comentario: