Automatización de procesos en ShellScript con Expect

La programación ShellScript es una forma idónea para ejecutar y automatizar tareas del sistema, y de echo tengo realizados unos cuantos procesos automáticos de esta forma. No es la única manera, ya que existen otros sistemas de programación interpretadas como perl o python, pero en este caso nos centraremos en esta forma para poder utilizar una particularidad de automatización llamada Expect

El problema surge cuando es necesario en la automatización tener que ejecutar tareas desde el usuario normal y requieren la contraseña del root para realizar varias tareas.
Pues bien, el planteamiento que vamos a desarrollar a continuación a modo de ejemplo, es como realizar unos procesos como root de forma automática, que de otra forma tendríamos que hacerlas manualmente siendo por tanto tedioso.
Para ello vamos a utilizar el paquete expect y el paquete zenity, este último no es necesario instalarlo ya que viene por defecto instalado en la mayoría de las distros basadas en Debian.

Expect es una función que se integra perfectamente en el ShellScript cuya particularidad es que su ejecución esta basada en la espera de respuesta de la salida estandar del terminal. Es decir, expect lanza una orden en la linea de comandos de la shell y se queda a la espera de recibir una respuesta concreta de la orden que ha dado, de tal forma que hasta que no reciba una respuesta no sigue la ejecución del script al siguiente paso.
Por ejemplo, si ejecutamos la orden «su» expect quedará a la espera de que la linea de comandos le de la respuesta «contraseña:» o «password:», para a continuación ejecutar la siguiente orden que es la escritura de la contraseña. Lógicamente tenemos que programas expect con las ordenes correctas para que haga lo que acabamos de decir.

Respecto a zenity es una forma de ejecutar ventanas en entorno gráfico desde la linea de comandos, devolviendo el resultado a esta a la linea de comandos. En nuestro caso vamos hacer que arranque una ventana en entorno gráfico para que nos pida la contraseña. Esto no es estrictamente necesario, pero es aconsejable porque de esta forma nadie verá la contraseña que estamos introduciendo, ya que queda oculta al escribirla.

¡¡¡Manos a la obra!!!. Lo primero que tenemos que hacer es instalar el paquete expect y zenity de la forma habitual desde el synaptic o en linea de comandos con apt como root de la forma:

#> apt-get install expect zenity

Ahora vamos a generar un script de ejemplo, posiblemente un poco tonto, pero ideal para ver como funciona esto y abrir así la mente para que vosotros le busquéis una utilidad adecuada.
El planteamiento es que el script al ejecutarlo va a realizar los siguiente pasos:

Desde el prompt del usuario «pepe» ejecutamos el script
1.- Se pide la contraseña de «root».
2.- Se identifica como root con «su».
3.- hace una copia del log «syslog» con «cat».
4.- Cambiamos los permisos con «chown» para el usuario «pepe».
5.- Se vuelve al prompt del usuario pepe con «exit».
6.- Se hace una copia del archivo con «scp» autenticándonos como root, para traerse el archivo al «HOME» del usuario «pepe».

Aquí muestro el script para realizar estas tareas.

#!/bin/bash

# PETICION DE CONTRASE�?A ROOT
contra=`zenity –entry –text «Introduzca contraseña de root» –title Identificacion –hide-text`

# EJECUCION DEL CODIGO
datos=$(expect -c »
spawn su
expect \»*Contraseña*\»
send \»$contra\r\»
expect \»root@\»
send \»cat /var/log/syslog \> /var/log/milog.txt\r\»
expect \»root@\»
send \»chown pepe:pepe /var/log/milog.txt\r\»
expect \»root@\»
send \»exit\r\»
expect \»pepe@\»
spawn scp root@localhost:/var/log/milog.txt milog_pepe.txt
expect \»*password*\»
send \»$contra\r\»
expect \»pepe@\»
puts \»TERMINADO\r\»

«)
echo «$datos»

Recordar que el script hay que salvarlo a un archivo con permisos de ejecución para poderlo ejecutar en linea de comandos.
Con zenity pedimos la contraseña del root que queda cargada en la variable «contra».
Los comandos «spawn» y «send» son la forma para mandar ordenes o información al sistema.
El comando «expect» es la orden de espera a que la linea de comandos devuelva la cadena que se especifica en este comando. Es decir expect \»*contraseña*\», está esperando a que el sistema devuelva la palabra «contraseña», si esta aparece, se ejecutará la siguiente orden que es escribir la contraseña con send \»$contra\r\».
El comando «puts» es el equivalente al comando «echo» para escribir texto en pantalla.

Bueeeenoo, esto está muy bien y funciona, pero si nos confundimos en escribir la contraseña del root, el script no se ejecutará de manera correcta.
¿Como podemos evitar que el script se ejecute si la contraseña no es válida?
Pues cambiando el código de la linea:

contra=`zenity –entry –text «Introduzca contraseña de root» –title Identificacion –hide-text`

por el siguiente código:

# PETICION DE CONTRASEÑA ROOT Y CHEQUEO PREVIO SI ES CORRECTA
fallocontra=1
while [ $fallocontra -gt 0 ]
docontra=`zenity –entry –text «Introduzca contraseña de root» –title Identificacion –hide-text`
datos=$(expect -c »
spawn su
expect \»*Contraseña*\»
send \»$contra\r\»
expect \»*@*\»
«)

echo «$datos» > error.txt
fallocontra=`grep -i ‘Fallo de autenticaci’ error.txt |wc -l`
rm error.txt
if [ $fallocontra -gt 0 ];
then
zenity –warning –text «Error al introducir la Contraseña.\r\rVuelva a intentarlo de nuevo.» –title «Error Autentificación»
fi

done

Esto pedirá la contraseña y chequeará si funciona haciendo un «su». Si el resultado es un «Fallo de autenticación» te mostrará un error con «zenity», y volverá a pedir la contraseña indefinidamente hasta dar la correcta.

Esto es todo. Con esto ya teneis un comienzo para cacharrear e investigar por los internetes de como hacer cosas mas complejas y utilidades que le podeis dar.

 

 

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *