Este es uno de los capítulos del tutorial Diálogos para scripts. Encontrarás los enlaces a todos los de capítulos, al final de este artículo.
Si en el capítulo anterior, te mostré una opción para crear cuadros de diálogo que se integraban perfectamente con el entorno de escritorio KDE, en este caso tienes una opción que se integra perfectamente con GNOME, Mate, Cinnamon, etc. Esta herramienta es zenity y utiliza la librería GTK para estos menesteres. De nuevo con esta herramienta puedes crear diálogos para tus scripts, que en este caso se integrarán perfectamente con los entornos de escritorio mencionados anteriormente. Así, aunque he titulado este capítulo del tutorial como diálogos para GNOME, lo cierto es que zenity no se circunscribe únicamente a este entorno de escritorio, sino que es válido para cualquier otro, sin embargo, se integra mejor con los escritorios basados en GTK.
Diálogos para GNOME con zenity
Zenity
Zenity es una revisión de gdialog que a su vez es la implementación de GNOME de dialog
, que te permite crear diálogos desde la línea de comandos para tus scripts realizados en Bash, o en cualquier otro shell que utilices.
Como con las otras herramientas que hemos visto en los distintos capítulos del tutorial, Zenity, te va a permitir crear diferentes tipos de diálogos mas o menos simples. Diálogos simples que te van a permitir interactuar de forma gráfica con el usuario.
Instalación de Zenity
Lo primero y principal, antes de ponerte a dotar a tus scripts en Bash de una interfaz gráfica con Zenity, es por supuesto instalarlo. Indicarte que esta herramienta se encuentra en los repositorios oficiales de Ubuntu, y de la mayoría de distribuciones. En este sentido, su instalación es tan sencilla como ejecutar la siguiente instrucción en el caso de que te encuentres en Debian, Ubuntu, Linux Mint, etc,
sudo apt install zenity
En el caso de que te encuentres en RedHat o CentOs, la instalación de Zenity, la puedes realizar ejecutando la siguiente instrucción,
sudo yum install zenity
Un diálogo sencillo
Al igual que hemos hecho con el resto de herramientas, te voy a mostrar todas las posibilidades de Zenity con diferentes ejemplos. Esto te va a permitir que te hagas una idea de las posibilidades de esta herramienta, y por otro lado te permitirá ver como integrarlo con tus propios scripts.
Por supuesto que al tratarse de un la implementación de GNOME de dialog
su uso es muy similar, tal y como puedes ver ya desde el primer ejemplo que te muestro. Aunque presenta algunas modificaciones, tal y como el título, y algunos otros detalles.
zenity --info \
--title="https://atareao.es" \
--width=250 \
--text="Este es el mensaje que se muestra"
Indicarte que tanto los parámetros --title
como --width
son totalmente opcionales. Sin embargo, he preferido incluirlos en este primer ejemplo, para que veas como utilizarlos.
Por otro lado, además de --info
que es el que te muestra el icono de información también puedes utilizar --warning
y --error
, que te muestran cuadros de diálogo de aviso y de error. Básicamente se trata del mismo cuadro de diálogo, pero donde cambia el icono de información por uno de aviso o de error, respectivamente. Así, por ejemplo, el de error tendría un aspecto como el que puedes ver a continuación,
zenity --error \
--title="https://atareao.es" \
--width=250 \
--text="Este es el <b>mensaje</b> que se muestra"
Si te fijas en el texto del cuadro de diálogo, la palabra mensaje
va entre etiquetas, como si fuera html
. Lo cierto es que los cuadros de diálogo de Zenity, admiten algo similar, que se conoce como lenguaje de marcado Pango que tiene una sintaxis muy similar. Así, por ejemplo, b
es para texto en negrita, i
es para cursiva, tt
para utilizar una fuente mono espacio y mas. No solo esto, sino que también puedes llamar la atención del usuario cambiando el color del texto, e incluso el fondo del texto.
En cualquier caso te recomiendo que visites la página de GNOME donde habla del lenguaje de marcado Pango, y encontrarás referencia a todo lo que indico anterirmente y mucho mas.
Preguntando al usuario
Si además de informar al usuario de un evento, quieres ir un paso mas allá y preguntar al usuario para que tome una decisión, puedes utilizar el diálogo --question
, tal y como ves en el siguiente ejemplo,
zenity --question \
--title="https://atareao.es" \
--width=250 \
--text="¿Quieres continuar?"
ans=$?
if [ $ans -eq 0 ]
then
echo "Si que quiere continuar"
else
echo "No quiere continuar"
fi
De nuevo, tienes que fijarte en que en caso de que el resultado sea 0
indica que ha pulsado el botón Si
y en otro caso, habrá pulsado el botón No
.
En este caso, puedes personalizar los botones ok
y cancel
añadiendo las correspondientes etiquetas, y también tienes otras opciones para no utilizar Pango. Así, por ejemplo, puedes personalizar el diálogo de la siguiente manera,
texto="¿<span weight=\"bold\" foreground=\"green\">Seguro</span> que quieres?"
zenity --question \
--title="https://atareao.es" \
--width=250 \
--ok-label="Continuar" \
--cancel-label="Abandonar" \
--text="${texto}"
ans=$?
if [ $ans -eq 0 ]
then
echo "Si que quiere continuar"
else
echo "No quiere continuar"
fi
Pidiendo información al usuario
El siguiente paso es preguntar al usuario por su nombre, o por cualquier otro dato que tenga que introducir. El funcionamiento de este cuadro de diálogo es similar al que has podido ver en otros capítulos del tutorial. En este sentido, si el resultado es distinto de 0
el usuario no quiere decirnos su nombre. Mientras que si el resultado es igual a 0
entonces la variable contendrá el contenido del campo. Por ejemplo,
nombre=$(zenity --entry \
--title="https://atareao.es" \
--width=250 \
--ok-label="Aceptar" \
--cancel-label="No te lo quiero decir" \
--text="¿Cual es tu nombre?")
ans=$?
if [ $ans -eq 0 ]
then
echo "Su nombre es: ${nombre}"
else
echo "No me quiere decir su nombre"
fi
Por supuesto, y como no podía ser de otra manera, también tienes el correspondiente diálogo para facilitar al usuario que introduzca una contraseña. Aquí tienes un ejemplo,
password=$(zenity --password \
--title="https://atareao.es" \
--width=250 \
--ok-label="Aceptar" \
--cancel-label="No te la quiero decir" \
--text="Introduce la contraseña:")
ans=$?
if [ $ans -eq 0 ]
then
echo "Tu contraseña es: ${password}"
else
echo "No me quiere decir su contraseña"
fi
Elegir entre diferentes opciones
Otra cuestión interesante es pedir al usuario que elija entre diferentes opciones. En este caso, al igual que con otras herramientas del tutorial, también puedes definir si el usuario solo puede elegir una o varias de las opciones que le ofreces.
componente=$(zenity --list \
--title="https://atareao.es" \
--height=200 \
--width=100 \
--ok-label="Aceptar" \
--cancel-label="Cancelar" \
--text="Selecciona un componente para tu pizza:" \
--radiolist \
--column="" \
--column="Componente" \
1 "Jamón" 2 "Queso" 3 "Huevo")
ans=$?
if [ $ans -eq 0 ]
then
echo "Has elegido: ${componente}"
else
echo "No has elegido ningún componente"
fi
Si en lugar de utilizar --radiolist
utilizas --checklist
podrás elegir varias opciones de forma simultánea. Lo que has elegido lo recogerás en la variable separados por |
por defecto, o por otro carácter si lo defines. Un ejemplo,
componente=$(zenity --list \
--title="https://atareao.es" \
--height=200 \
--width=100 \
--ok-label="Aceptar" \
--cancel-label="Cancelar" \
--text="Selecciona un componente para tu pizza:" \
--checklist \
--column="" \
--column="Componente" \
--column="Calorías" \
1 "Jamón" 100 2 "Queso" 150 3 "Huevo" 125)
ans=$?
if [ $ans -eq 0 ]
then
echo "Has elegido: ${componente}"
else
echo "No has elegido ningún componente"
fi
Indicarte que además en este segundo ejemplo, he añadido una columna adicional, para que tengas información sobre las calorías del producto. Eso si, no te dejes guiar por estos valores, porque los he puesto completamente al azar. Cualquier parecido con la realidad es pura coincidencia.
Respecto a los valores que devuelve, indicarte que por defecto devuelve los de la primera columna. En el ejemplo que te he puesto, te devolvería Jamón, o Queso, o incluso en el caso de que seleccionaras los dos, te devolvería Jamón|Queso. Pero, puedes elegir la columna que tu quieras utilizando la opción --print-column
, de forma que si seleccionas la opción ALL
te devolverá todas las columnas.
¿Como seleccionar archivos?
Otra interesante utilidad que le puedes dar a esta herramienta, es para seleccionar archivos y directorios. Para el caso de archivos, y utilizando el modo de abrir o seleccionar, tienes algunas opciones interesantes, como son,
--multiple
que te permite seleccionar varios archivos de forma simultánea--file-filter
con el que puedes definir un patrón de filtrado, tal y como te muestro en el ejemplo a continuación.--save
para el caso de que lo quieras mostrar sea el típico diálogo de Guardar como.--confirm-overwrite
para confirmar en el caso de que el archivo ya exista.
archivo=$(zenity --file-selection \
--title="https://atareao.es" \
--height=200 \
--width=100 \
--text="Selecciona un archivo:" \
--file-filter="scripts | *.sh")
ans=$?
if [ $ans -eq 0 ]
then
echo "Has elegido este archivo: ${archivo}"
else
echo "No has elegido ningún archivo"
fi
Por otro lado, si lo que quieres es seleccionar un directorio, tienes que utilizar la opción --directory
tal y como te muestro en el siguiente ejemplo,
directorio=$(zenity --file-selection \
--title="https://atareao.es" \
--height=200 \
--width=100 \
--text="Selecciona un directorio:" \
--directory)
ans=$?
if [ $ans -eq 0 ]
then
echo "Has elegido este directorio: ${directorio}"
else
echo "No has elegido ningún directorio"
fi
Decirte que en el caso de que selecciones un archivo, realmente estás seleccionando el directorio que contiene el archivo. Pienso, y es una opinión personal, que no se deberían mostrar archivos, sino solo directorios.
Elegir colores
Como no todo en esta vida consiste en introducir datos o seleccionar entre diferentes opciones, zenity
también te ofrece otros cuadros de diálogos alternativos. En este caso, tienes el de seleccionar color, como el que te muestro en el siguiente ejemplo,
color=$(zenity --color-selection \
--title="https://atareao.es" \
--height=200 \
--width=100 \
--text="Selecciona un color:")
ans=$?
if [ $ans -eq 0 ]
then
echo "Has elegido este color: ${color}"
else
echo "No has elegido ningún color"
fi
Si lo que quieres es mostrar la paleta de colores, en ese caso tienes que utilizar la opción --show-palette
, y el resultado será similar al que ves en la siguiente captura de pantalla.
Mostrando el progreso de tus trabajos
Por supuesto que Zenity también tiene su cuadro de diálogo para mostrar progreso, sin embargo, en este punto te tengo que decir, que el de kdialog me resulta mucho, pero que mucho mas interesante y currado que este… Habría que buscar una solución para el caso de diálogos con GNOME, y otros derivados, y conseguir una mejor integración.
Así, para mostrar el progreso, puedes hacer algo similar a lo que te muestro a continuación. El inconveniente de esto, es que los porcentajes los estimas tu, con lo que el usuario puede terminar bastante desorientado.
(
sleep 1
echo "10"
echo "# Paso 1"; sleep 1
echo "20"
echo "# Paso 2"; sleep 1
echo "30"
echo "# Paso 3"; sleep 1
echo "50"
echo "# Paso 4"; sleep 1
echo "70"
echo "# Paso 5"; sleep 1
echo "90"
echo "# Terminado"
echo "100"
) |
zenity --progress \
--title="https://atareao.es" \
--text="Iniciando el proceso" \
--percentage=0
if [ "$?" = -1 ] ; then
zenity --error \
--text="Update canceled."
fi
Seleccionando números enteros
Existen diferentes opciones para que un usuario introduzca un número entero, empezando por utilizar una caja de texto. Sin embargo, el problema de esto, es que posteriormente, necesitas comprobar, si el valor introducido es un número, y no solo esto, sino que está entre los valores permitidos. Me refiero, por ejemplo, al caso, que preguntes al usuario que introduzca un número de 1 a 10.
En el caso de Zenity, tienes un cuadro de diálogo que se adecua precisamente a esto. Te permite que el usuario pueda introducir un número entero entre dos valores concretos. Se trata de --scale
. Así, en el caso que te acabo de comentar, podrías utilizar el siguiente ejemplo,
numero=$(zenity --scale \
--title="https://atareao.es" \
--text="Elige un numero de 1 a 10" \
--min-value=1 \
--max-value=10 \
--value=3)
ans=$?
if [ $ans -eq 0 ]
then
echo "Has elegido este numero: ${numero}"
else
echo "No has elegido ningún numero"
fi
Preguntando al usuario por una fecha
Algo con lo que me suelo pelear son con las fechas. Realmente es algo que siempre me ha resultado problemático. Empezando por los formatos y terminando por las zonas horarias. Es algo que siempre me suele dar problemas. Por supuesto, si pones las cosas mas o menos sencillas todo suele ir algo mejor. Así, si utilizas un diálogo como --calendar
esto te resultará algo mas sencillo. Así, por ejemplo, para preguntar una fecha al usuario, puedes utilizar algo como lo que te muestro a continuación,
fecha=$(zenity --calendar \
--title="https://atareao.es" \
--text="Elige una fecha")
ans=$?
if [ $ans -eq 0 ]
then
echo "Has elegido este fecha: ${fecha}"
else
echo "No has elegido ninguna fecha"
fi
Formularios con Zenity
Por último, y para terminar este capítulo del tutorial, los formularios. Esta es una opción que no está disponible en todos las herramientas que hemos visto y que veremos en los próximos capítulos. Sin embargo, creo que es una opción, no solo necesaria, sino imprescindible. Y digo que es imprescindible, porque me resulta, un tanto infumable para un usuario, tener que introducir diferentes datos en diferentes cuadros de diálogo, cuando se podría introducir todo en uno. Es mas, creo que, mostrar muchos diálogos, puede llevar al usuario a abandonar la aplicación.
Así, como ejemplo, te muestro un cuadro de diálogo para preguntar a un usuario por sus datos personales, y como extraerlos posteriormente, en el caso de que el usuario pulse el botón de Aceptar,
datos=$(zenity --forms \
--title="https://atareao.es" \
--text="Introduce los siguientes datos" \
--add-entry="Nombre" \
--add-entry="Apellido" \
--add-password="Contraseña" \
--add-calendar="Fecha de nacimiento")
ans=$?
if [ $ans -eq 0 ]
then
echo "Has introducido los siguientes datos:"
IFS="|" read -r -a array <<< "$datos"
echo Nombre: "${array[0]}"
echo Apellido: "${array[1]}"
echo Contraseña: "${array[2]}"
echo Fecha de nacimiento: "${array[3]}"
else
echo "Has cancelando"
fi
Conclusión
Como ves, y tal y como te he indicado en el artículo, Zenity, intenta seguir el comportamiento de su antecesor dialog
, y es realmente sencillo de utilizar. Por supuesto, se integra perfectamente con el entorno de escritorio GNOME y con otros entornos de escritorio derivados, como puede ser Cinnamon o MATE.
De todas las opciones que ofrece Zenity, probablemente la que mas me ha llamado la atención es la posibilidad de hacer formularios, y la que mas me ha defraudado es la barra de progreso. En este sentido, la barrad de progreso de kdialog
va a la cabeza de todas estas herramientas, al menos desde mi punto de vista, claro.
Imagen de portada de Med Badr Chemmaoui en Unsplash
Genial el post….pero
Desde CRONTAB no consigo que funcione Zenity !!!
he creado esta funcion:
function Globo_Zen () {
export DISPLAY=:0
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
zenity –$1 –title=»$2″ –text=»$3″ –width=250 –height=200 –timeout=$4
}
y todo lo que consigo de CRONTAB (como sudo) es lo siguiente:
No protocol specified
Unable to init server: Could not connect: Connection refused
(zenity:6671): Gtk-WARNING **: 12:14:01.502: cannot open display: :0
Toda esta info la recojo en un fichero con >errores 2>&1
Si puedes echarle un vistazo, te lo agradecería.
Buen trabajo en el blog. Gracias.
Un saludo.
P.S. (Yo tambien deje (afortunadamente) atrás windows). Uso MINT.
Desde cron no sé si se podrá conectar al servidor Xorg para mostrar ventanas. Con qué usuario se ejecuta la tarea de cron?