Archivo del blog

lunes, 13 de marzo de 2017

Dale vida a tus scripts con Zenity

Hace tiempo que quiero hablaros de esta pequeña pero matona herramienta llamada Zenity, que nos ayuda a ponerle una interfaz gráfica a nuestro scripts mediante funciones, menús o cajas de diálogos ya preconfigurados y combinables entre sí.
En ella podemos encontrar diálogos de calendario, formularios, listas, cuadros de mensajes o alertas, selección de archivos, entrada de texto, barra de progresos, iconos de notificación, etc.
Zenity es una herramienta de GNOME que podemos descargar desde este enlace, pero que está en los repositorios de algunas distribuciones y en otras como Ubuntu ya está instalado por defecto.
Veamos algunos ejemplos de lo que podemos hacer con Zenity. Para ello abrimos nuestro terminal y tecleamos lo siguiente:
zenity --calendar

zenity --password --username

zenity --scale

zenity --width=360 --height=320 --list --title "Ejemplo" --column file "Visita LinuxZone"

zenity --question --width=350 --height=120 --title "El sistema encontró un error critico" --ok-label="Definitivamente" \
--cancel-label="Sí" --text "Windows se encuentra instalado en su disco. ¿Desea desinstalarlo?" ; echo $


Por supuesto esto solo es el marco, lo que queremos que aparezca dentro eso ya depende de nosotros. Por ejemplo, vamos a crear en unos pocos pasos un lanzador con tres sencillas funciones, que nos abra una aplicación, que nos abra una carpeta y que nos lleve a una página web, con la ayuda del comando xdg-open. Abre un editor y escribe lo siguiente:
#!/bin/bash
file=$(zenity –width=360 –height=320 –list –title “Lanzador” –column Acciones “Abrir Gedit” “Abrir carpeta Música” “Ir a LinuxZone”)
if [ “$file” = “Abrir Gedit” ]; then
/usr/bin/gedit
elif [ “$file” = “Abrir carpeta Música” ]; then
xdg-open ~/Música/
elif [ “$file” = “Ir a LinuxZone” ]; then
xdg-open http://linuxzone.es/
else
exit 0
fi
Le ponemos el nombre que queramos, seguido de la extensión .sh y le damos permisos de ejecución.

Como vemos, tan solo hay que seleccionar una de las opciones y le damos a aceptar para que la ejecute.
Pero tal vez no te guste ese dialogo y prefieras una pantalla de selección en la que puedas abrir varias opciones de golpe, pues nada más sencillo, solo tenemos que añadir otra columna y la función –checklist, que podemos ponerla marcada (TRUE) o desmarcada (FALSE) por defecto:
#!/bin/bash
file=$(zenity –width=360 –height=320 –title “Lanzador” –list –column=”” –column=”Acciones” –checklist FALSE “Abrir Gedit” FALSE “Abrir carpeta Música” TRUE “Ir a LinuxZone”)
if [ “$file” = “Abrir Gedit” ]; then
/usr/bin/gedit
elif [ “$file” = “Abrir carpeta Música” ]; then
xdg-open ~/Música/
elif [ “$file” = “Ir a LinuxZone” ]; then
xdg-open http://linuxzone.es/
else
exit 0
fi

En este enlace disponen de varios ejemplos de cuadros de dialogo y muchas opciones para experimentar. Así que ya sabes, si le quieres dar mas vistosidad a tus scripts o simplemente te has animado a empezar a hacer tus “pinitos” en bash, sin duda Zenity te lo pone fácil.
Proyecto Zenity

Este es un post continuo de Un ejemplo de diálogo de zenidad completa 1 , en este post cubriremos el diálogo de zenidad para el progreso, pregunta, advertencia, escala, información de texto y lista.
¿Cómo crear el diálogo de progreso zenity?
El diálogo de progreso es hacer un seguimiento de una progresión de una rutina, puede ser cualquier cosa, digamos que quiero almacenar la lista de resultados de archivos abiertos (lsof) en una llamada de archivo lsof.txt, y utiliza el progreso zenity para realizar un seguimiento de la progresión, lo hago :
gksudo lsof | tee >(zenity --progress --pulsate) >lsof.txt 


Tengo que usar tee, porque sin usar tee, zenity se despojará de mi resultado. Echa un vistazo a los ejemplos de tee para obtener más información.
¿Cómo crear diálogo de preguntas de zenidad?
 zenity --question --text "Are you sure you want to shutdown?"; echo $? 
Como echo $? Devuelve el resultado 0 significa que el usuario presiona yes, 1 significa cancel.

¿Cómo crear un diálogo de advertencia de zenidad?
 zenity --warning --text "This will kill, are you sure?";echo $? 

¿Cómo crear el diálogo de la escala de la zenidad?
Diálogo de escala le permite establecer un rango de número, por lo que el usuario es fuerza para elegir un número dentro del rango.
 ans=$(zenity --scale --text "pick a number" --min-value=2 --max-value=100 --value=2 --step 2);echo $ans 

¿Cómo crear un diálogo de información de texto de zenity?
La información de texto puede ser muy útil para mostrar texto a una GUI. Utilizo de nuevo los ejemplos lsof, pero esta vez alimentar los resultados al cuadro de información de texto.
 gksudo lsof | zenity --text-info --width 530 

Como puede ver, puede especificar el ancho y la altura de un diálogo de zenidad. Demasiado malo, el cuadro de diálogo de información de texto no tiene opción para deshabilitar el ajuste de texto y especificó qué tipo de letra utilizar.
¿Cómo crear el diálogo de lista de zenity?
El diálogo de lista es el diálogo más flexible y he gastado bastante a veces para utilizar el uso. Como puede generar varias columnas, selección múltiple, lista de comprobación, radiolist, etc. checkout -help-list para más información.
Esto es para radiolista:
 ans=$(zenity --list --text "Is linux.byexamples.com helpful?" --radiolist --column "Pick" --column "Opinion" TRUE Amazing FALSE Average FALSE "Difficult to follow" FALSE "Not helpful"); echo $ans 

Primero debe definir columnas, luego alimentar todas las opciones de lista una por una.
Esto es para la lista de verificación:
 ans=$(zenity --list --text "How linux.byexamples can be improved?" --checklist --column "Pick" --column "options" TRUE "More pictures" TRUE "More complete post" FALSE "Includes Installation guidelines" FALSE "Create a forum for question queries" --separator=":"); echo $ans 

El resultado de este tiempo será largo y probablemente más de uno, por lo que puede spefify un separador para diferenciarlos.

Preámbulo

Uno de los errores más comunes cuando se aprende a utilizar los scripts “bash” bajo GNU/Linux para leer un archivo línea por línea, es el utilizar un bucle “for”, (for line in $(cat file.txt); do ...) lo que conduce a una evaluación de cada palabra y no de cada línea, que es lo que se busca.

Ejemplo de un bucle “for”:
for line in $(cat file.txt); do echo "$line" ; done
Esta
Es 
La 
Línea
n°
1
Esta
Es 
La 
Línea
n°
2
Esta
[...]

La solución consiste en utilizar un bucle “while” asociado al comando interno “read”.

Sin embargo, también podemos obtener el mismo resultado con un bucle “for” con la condición de que cambiemos el valor de la variable "$IFS" (Internal Field Separator, separador de campo interno) antes de ejecutar el bucle. Es lo que veremos a continuación.

Bucle while

El bucle “while” sigue siendo el método más apropiado y simple para leer un archivo línea por línea.

Sintaxis

while read linea
do
   comando
done < archivo


Ejemplo

El archivo de inicio:
Esta es la línea n° 1
Esta es la línea n° 2
Esta es la línea n° 3
Esta es la línea n° 4
Esta es la línea n° 5

Las instrucciones en línea de comandos:
while read line; do echo -e "$line\n"; done < file.txt

o en un script “bash”:
#! /bin/bash

while read line
do 
   echo -e "$line\n"
done < file.txt

La salida en la pantalla será (stdout):
Esta es la línea n° 1
Esta es la línea n° 2
Esta es la línea n° 3
Esta es la línea n° 4
Esta es la línea n° 5


Trucos

También podemos a partir de un archivo estructurado (como una libretas de direcciones o /etc/passwd por ejemplo) obtener los valores de cada campo y asignarlos a varias variables con el comando “read”. Sin embargo hay que tener cuidado de asignar a la variable “IFS” el separador de campo adecuado (espacio por defecto).

Ejemplo:
#! /bin/bash

while IFS=: read user pass uid gid full home shell
do
echo -e "$full :\n\
 Pseudo : $user\n\
 UID :\t $uid\n\
 GID :\t $gid\n\
 Home :\t $home\n\
 Shell :\t $shell\n\n"
done < /etc/passwd


Complemento

while read i; do echo -e "parametro : $i"; done < <(echo -e "a\nab\nc")


Bucle for

Si bien es cierto que el bucle “while” es el método más simple, sin embargo este tiene un gran inconveniente, el de eliminar el formateado de las líneas y especialmente los espacios y tabulaciones.
Felizmente el bucle “for” asociado a un cambio de IFS permite conservar la estructura del documento a la salida.

Sintaxis

oldIFS=$IFS     # conserva el separador de campo
IFS=$'\n'     # nuevo separador de campo, el caracter fin de línea
for línea in $(cat archivo)
do
   comando
done
IFS=$old_IFS     # restablece el separador de campo predeterminado

¿Cómo se puede comprobar en un script de Bash si el contenido de una variable es un número?

Una posible solución sería utilizar una expresión regular como la siguiente:



Esta expresión regular tiene en cuenta los números enteros, los decimales y los números negativos. Si necesitas una comprobación más simple, puedes utilizar las siguientes expresiones regulares alternativas:

    ^[0-9]+$, números enteros positivos.
    ^[0-9]+([.][0-9]+)?$, números enteros o decimales positivos.

¿Cómo comprobar si una variable de Bash contiene una determinada cadena de texto?




Sed – Eliminar una o varias líneas de un fichero

Sintaxis

sed '{[/]<n>|<cadena>|<regex>[/]}d' <nombre_ fichero>
sed '{[/]<direccion1>[,<direccion2>][/]d' <nombre_fichero

/.../ = delimitadores
n = el número de línea
cadena = la cadena contenida en la línea
regex = expresión regular correspondiente a la ocurrencia buscada
direccion = la dirección de una línea (número u ocurrencia)
d = delete (borrar)

Ejemplos
Eliminación de la 3ra línea

sed '3d' mi_fichero.txt

Eliminación de la línea conteniendo la cadena "awk"

sed '/awk/d' mi_fichero.txt

Eliminación de la última línea

sed '$d' mi_fichero.txt

Eliminación de todas las líneas vacías

sed '/^$/d' mi_fichero.txt
sed '/./!d' mi_fichero.txt


Eliminación de la línea conteniendo una expresión regular
(aquí se elimina la línea conteniendo caracteres numéricos (al menos 1 cifra) situados al final de la línea)

sed '/[0-9/][0-9]*$/d' mi_fichero.txt

Eliminación del intervalo comprendido entre las líneas 7 y 9

sed '7,9d' mi_fichero.txt

Lo mismo pero esta vez la dirección es reemplazada por una ocurrencia

sed '/-Inicio/,/-Fin/d' mi_fichero.txt

Nota
Los ejemplos precedentes únicamente modifican la visualización del archivo (salida estándar 1 = la pantalla).
Para realizar modificaciones permanentes, en las antiguas versiones (<4) utilizar un fichero temporal, para GNU sed utilizar el parámetro "-i[sufijo]" (--in-place[=sufijo]), como en el ejemplo siguiente:

sed -i".bak" '3d' mi_fichero.txt

No mostrará el resultado en la salida estándar, y modificará el fichero original "mi_fichero.txt" eliminando la 3ra línea y creará un fichero de respaldo llamado "mi_fichero.txt.bak"
Fichero a ser utilizado en los ejemplos (mi_fichero.txt):


Eliminar caractéres

tr -d "\n" < fichero.txt > fichero2.txt
tr ',' '.' < fichero2.txt > fichero3.txt

¿Cómo dividir en bash una cadena mediante un delimitador específico?

La solución más sencilla para dividir la cadena y convertirla en un array sería el siguiente código:

IN="bla@some.com;john@home.com"
arrIN=(${IN//;/ })

Otra posible solución consiste en utilizar la variable IFS (Internal Field Separator). Al cambiar el valor de esta variable en un comando, los cambios afectan solamente a ese comando, así que no tiene efectos secundarios. El resultado sería:

IFS=';' read -ra ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
    # procesar "$i"
done

Una generalización de la solución anterior sería:

while IFS=';' read -ra ADDR; do
    for i in "${ADDR[@]}"; do
        # procesar "$i"
    done
done <<< "$IN"

 













No hay comentarios:

Publicar un comentario