Langage / Toolkit graphique : bash/dialog

Je vous avais promis la dernière fois un couple langage/kit graphique classique ... J'ai menti ! Je vous présente bash/(x)dialog.

bash, que du bash

Voyons en bash comment obtenir le programme générique à réaliser dans cette série d'articles : demander son nom à l'utilisateur et lui dire bonjour.

Tapez ceci dans un fichier bonjour_bash :

#!/bin/bash
echo Tapez votre nom :
read nom
echo Bonjour $nom !

Il nous faut ensuite rendre le script exécutable et le lancer :

zazou@ZazouMobile:~/devel_bash$ chmod a+x bonjour_bash
zazou@ZazouMobile:~/devel_bash$ ./bonjour_bash
Tapez votre nom :
Xavier Garreau
Bonjour Xavier Garreau !

Voila ! Nous avons les bases de cet article ;-), bien que la suite n'ait plus grand chose à voir au niveau du code ... Le contenu de ce script est très simple, la première ligne sert à savoir quel interpréteur on doit utiliser pour l'exécuter, les deux lignes commençant par echo affichent le texte qui suit, en remplaçant les variables par leurs valeurs. L'instruction read attend une ligne de l'utilisateur et en place le contenu dans la variable indiquée ensuite (il y a d'autres options : man bash)

dialog

Bash et dialog sont utilisés dans toutes les distributions que j'ai fréquentées. Vous connaissez tous ces interfaces si vous avez installé une slackware, une debian, une tclinux ou si vous avez déjà utilisé une MandrakeMove ou que vous connaissez linux depuis longtemps car presque toutes les distributions sont passées par une installation basée sur bash/dialog. Certaines l'utilisent toujours et dans bien des cas, c'est heureux pour les machines n'ayant pas trop de puissance.

dialog permet d'afficher des boîtes de dialogue dans votre console. C'est simple, et efficace. dialog est par exemple utilisé sous une forme simplifiée, lxdialog, pour la configuration du kernel (make menuconfig).

Oui mais pourquoi a-t-on besoin de dialog ? On peut faire la même chose en "langage quelconque/toolkit graphique quelconque". A cette question, plusieurs réponses. La première, "pour voir plus loin, ce qui se cache derrière ce que l'on sait" ... La seconde est liée à d'éventuelles contraintes techniques, on n'a pas toujours sous la main un écran de 24 pouces avec le dri activé sur un XFree 6.4 avec les dernières libs gtk+ 3.6.3rc4 pour faire une géniale interface communiquant via corba_ng (pour next generation). Bref, pouvoir faire un outil un tant soit peu évolué, rapidement et sans besoin de ressources prohibitif.

Trêve de discussions, place au code :

#!/bin/bash
nom=`dialog  --backtitle "Bonjour en bash/dialog" \
	--title " La question " \
	--inputbox "Entrez votre prénom :" 0 0 \
	2>&1`
if [ $? = 0 ]; then
	dialog --backtitle "Bonjour en bash/dialog" \
	       --title " Le Bonjour " \
	       --msgbox "\nBonjour $nom !" 10 30
fi

Notre première instruction appelle directement le programme dialog. A chaque appel de dialog correspond par défaut un écran avec un "dialogue". On voit ici 2 arguments. backtitle sert à préciser le titre qui doit apparaître en haut de l'écran. title permet, lui, de spécifier le titre du dialogue. Enfin, on choisit le type de dialogue à générer. Ici, on veut un dialogue acceptant une entrée de l'utilisateur, on utilise donc inputbox. Ce terme doit être suivi d'un texte explicatif, de la hauteur et la largeur du widget, en caractères ... Indiquer des tailles nulles permet de laisser dialog choisir des valeurs appropriées pour ces dernières.

dialog renvoie un code de retour dépendant du bouton cliqué, pour "oui", "ok", "accepter", ... c'est 0. Les informations entrées par l'utilisateur sont, elles, envoyées sur le flux d'erreur standard (2). en ajoutant 2>&1, on redirige ce flux vers la sortie standard. On récupère ainsi la chaîne saisie par l'utilisateur dans la variable nom.

Dans la suite de ce "long" script, on teste la valeur de retour de l'expression dialog précédente $? et, si l'utilisateur a cliqué sur "Accepter", on affiche un dialogue de salutation, une "boîte à message", msgbox, laquelle prend les mêmes arguments que le dialogue précédent. La seule différence réside dans le choix de la taille, que l'on impose.

bash/dialog scshot

Les fins connaisseurs apprécieront le fait que l'on puisse cliquer sur les boutons avec la souris ...

Xdialog

Bon ok, ok, j'avais dit toolkit graphique et certains d'entre vous ont compris par là, "des fenêtres où qu'on clique dessus avec le mulot". Soit, j'appelle à ma rescousse le programme Xdialog pour les adeptes du clickodrome ...

Contrairement à dialog, Xdialog n'est pas souvent installé par défaut par vos distributions préférées... Il vous faut donc le télécharger, éventuellement le compiler et l'installer. Sous debian, c'est affreusement simple, il suffit de taper apt-get install xdialog. Pour les autres, il existe surement des paquets à installer également mais dans le cas contraire, il reste la possibilité de compiler vous même les sources de ce fabuleux programme ... Commencez par télécharger les sources sur la page du projet (http://xdialog.dyns.net/) et le trio ./configure ; make ; make install habituel fera l'affaire pour vous procurer une installation fonctionnelle ...

Xdialog s'appuie sur gtk+ pour vous procurer un confort visuel "amélioré". Personnellement, je préfère la version ncurses, c'est plus "root" mais bon, chacun ses choix, on est adepte de make menuconfig ou on ne l'est pas ;-) ... L'important est que vous devrez avoir une installation de gtk1.x et gtk-config (à l'heure actuelle) pour utiliser Xdialog.

Pour utiliser Xdialog en lieu et place de dialog, vous n'avez qu'à remplacer toutes les occurences de dialog par Xdialog ...

Comme bien souvent une image parle plus qu'un long discours ...

bash/Xdialog scshot

Les "widgets" à notre disposition

Je ne résiste pas à l'envie de vous montrer quelques autres exemples de widgets. Cette liste n'est toutefois pas exhaustive ... Découvrez les autres vous mêmes !

textbox

Ci-dessous le code d'un viewer de fichier très simple mais fonctionnel ...

#!/bin/bash
if [ "$1" != "" ]; then
	if [ -f $1 ]; then
		dialog --backtitle "Widgets de bash dialog" \
	       	--title " Ze viewer : $1" \
	       	--textbox $1 18 70
	else
		echo "Fichier introuvable";
	fi
else
	echo USAGE: $0 fichier
fi
bash/dialog scshot

calendar

Cette année, mon anniversaire sera le 4/4/4, mais ça se voit mieux comme ça :

dialog --backtitle "Widgets de bash dialog" \
	--title "Anniversaire" \
	--calendar "" 0 0 4 4 2004
bash/dialog scshot

gauge

Voilà un élément très utilisé parmi les possibilités offertes par dialog. La barre de progression ou gauge ... Le programme ci-dessous fonctionne "à peu près" comme cp pour les fichiers à ceci près qu'il affiche une barre de défilement.

Pour afficher une barre de progression, on utilise dialog --gauge. Pour mettre à jour cette barre, il faut envoyer sur l'entrée standard de dialog les différents pourcentages à afficher. Lorsqu'on ferme l'entrée standard, dialog rend la main.

Il faut donc rediriger la sortie standard d'un sous-shell dans l'entrée de dialog. Par exemple, le code ci-dessous affiche une barre de défilement à 25% attends une seconde, la mets à jour à 50, puis quitte :
(echo 25 ; sleep 1 ; echo 50) | dialog --gauge "" 0 0.

Voici le script de copie de fichier avec état d'avancement.

#!/bin/bash
if [ "$1" != "" -a "$2" != "" ]; then
        if [ -f $1 ]; then
                src=$1
                size=`ls -al $src | awk '{print int(($5/512)+(($5%512)?1:0))}'`
		src_name=`find $src -printf %f`
        else
                echo "Fichier source introuvable" >2
                exit 1
        fi
        if [ -f $2 ]; then
                dest=$2
        else
                if [ -d $2 ]; then
                        dest=$2/$src_name
                else
                        dest=$2
                        touch $dest 2> /dev/null
                        if [ $? != 0 ]; then
                                echo "Destination invalide" >&2
                                exit 1
                        fi
                fi
        fi
        echo $src $dest $size
        chunk_size=$(($size/100))
        if [ $chunk_size -lt 1 ]; then
                cp $src $dest
                exit 0
        fi
        copied=0
        (while [ $copied -lt $size ]; do
                dd if=$src of=$dest bs=512 count=$chunk_size skip=$copied seek=$copied >/dev/null 2>&1
                copied=$(($copied+$chunk_size))
		echo $(((100*$copied)/$size))
        done) | dialog --backtitle "Widgets de bash dialog" --title " Copie en cours " --gauge "$src\n> $dest " 10 60 0
else
        echo USAGE: $0 fichier_src dest
fi

NB: Les accrocs du tcl peuvent remplacer :
size=`ls -al $src | awk '{print int(($5/512)+(($5%512)?1:0))}'`
par
size=`echo "puts [eval expr int(ceil([file size $src]./512))]" | tclsh`
(Merci David)

bash/dialog scshot

@+

Xavier Garreau - <xavier@xgarreau.org>
http://www.xgarreau.org/

Ingénieur de recherche PRIM'TIME TECHNOLOGY
http://www.prim-time.fr/

Membre fondateur du ROCHELUG
http://www.rochelug.org/

Liens & Références :

a+

Auteur : Xavier GARREAU
Modifié le 10.09.2004