vendredi 3 février 2012

[Tutoriel] Créer un Menu Dynamqiue en Bash

Pour ce premier tutoriel, nous allons apprendre à créer un menu dynamique en Bash, le langage de script le plus courament utilisé sur les environnement Unix-GNU/Linux.

Aujourd'hui les interfaces graphiques sont un peu partout. Partout ? Non. En effet, il est bien rare de trouver sur un serveur Unix-GNU/Linux un environnement XServer. On est donc obligé, le plus souvent d'utiliser la ligne de commande histoire de se la péter hacker comme dans les films hollywoodiens. Mais utiliser encore et toujours les même commandes, à force, ça en devient fatiguant, ça fait perdre du temps, et augmente le risque de faire des erreurs. On en vient donc à créer des scripts shell, et afin de le rendre utilisable pour un grand nombre d'utilisateur, on met naturellement en place une Interface Utilisateur dont des menus.

Le plus souvent, ces menus sont codés en durs, c'est à dire que pour changer les éléments de ces menus il faut éditer le scripts, ce qui n'est vraiment pas très pratique. Voici donc comment obtenir un menu dynamique.

Admettons que vous désiriez faire un menu permettant de lister l'ensemble des fichiers contenus dans les différents répertoires de votre dossier Menu du Dossier Utilisateur :    


Nous serions tenter de créer le menu comme suit :

#!/bin/bash


#########################
# CREATION DE MENU      #
#########################


# Création du Menu listant les différents répertoires du dossier $HOME/Menu


PS3="Quel répertoire voulez-vous lister : "


select item in "- Répertoire1 " "- Répertoire2 " "- Répertoire3 " "- Quitter "
do


    case "$REPLY" in


        1)
            # Liste des fichiers du réperoire 'Répertoire1'
            ls $HOME/Menu/Repertoire1
            ;;
        2)
            # Liste des fichiers du répertoire 'Répertoire2'
            ls $HOME/Menu/Repertoire2 
            ;;
        3)
            # Liste des fichiers du répertoire 'Répertoire3'
            ls $HOME/menu/Repertoire3
            ;;
        4)
            # On quitte le programme
            exit 0
            ;;
        *)
            # Pour n'importe que autre choix, signaler l'erreur et patienter
            echo "Saisie Incorrecte \c"
            read x
            ;;

    esac

done
Sauf qu'avec un tel script, si vous avez un jour un répertoire Repertoire4 avec ses fichiers, vous ne pourrez les voir avec le menu qu'en rajoutant manuellement une entrée dans le script. Il y a mieux pour être efficace.

select propose une sélection d'item ($item, variable choisie par l'utilisateur) parmis une liste, puis associe cet item à l'entrée utiilsateur ($REPLY, variable système). si l'entrée utilisateur  ne correspond à aucun item de la liste, alors il n'y a aucune correspondance à $REPLY.

$ select CHOIX in "- Repertoire1 " "- Repertoire2 " "- Repertoire3"; do echo "Votre Choix : $CHOIX. Le retour de select : $REPLY"; done



1) - Repertoire1
2) - Repertoire2
3) - Repertoire3
#? 1
Votre Choix : - Repertoire1 . Le retour de select : 1
#? 4
Votre Choix : . Le retour de select : 4



Puisque select fait une selection d'item parmis une liste, peut être pouvons nous mettre en variable cette liste.

$ liste_choix="- Repertoire1 - Repertoire2 - Repertoire3";select CHOIX in $liste_choix; do echo "Votre Choix : $CHOIX. Le retour de select : $REPLY"; done
1) -
2) Repertoire1
3) -
4) Repertoire2
5) -
6) Repertoire3
#?


C'est mieux mais pas top. Si on ajoute un répertoire Répertoire4, il faudra ajouter ce nouveau choix à la variable $liste_choix.

$ nouveau_choix="- Repertoire4 ";liste_choix="- Repertoire1 - Repertoire2 - Repertoire3 "$nouveau_choix;select CHOIX in $liste_choix; do echo "Votre Choix : $CHOIX. Le retour de select : $REPLY"; done


1) -
2) Repertoire1
3) -
4) Repertoire2
5) -
6) Repertoire3
7) -
8) Repertoire4
#?

On avance mais c'est pas encore tout à fait ça. Comme vous pouvez le constater select prend comme item chaque entité séparée par un espace. Il faut donc veiller, dans voter mise en forme que seul ces espaces necessaires demeurent. Les "-" étant de simples fioritures, n'apportant strictement rien, je vous conseil de ne point en mettre. De toutes façon avec ce qui va suivre vous allez vite voir que l'on peut s'en passer.

En effet nous venons de voir que select peut prendre une variable en guise de liste. Dans ce cas, pourquoi ne pas passer simplement par une substitution de commande ? (on redirige la sortie de la commande dans la variable qui alimente select)

Et quelle est la meilleure des commandes pour lister des répertoires dans un répertoire ? ls.

$ repMenu=$HOME/Menu;select CHOIX in $(ls $repMenu); do echo "Votre Choix : $CHOIX. Le retour de select : $REPLY"; done
1) Repertoire1
2) Repertoire2
3) Repertoire3
4) Repertoire4
#?
 Pour plus de simplicité on place le chemin vers le répertoire Menu dans une variable que l'on appelle avec ls. GREAT nous avons notre menu presque fonctionnel :)

...Quoique. Que se passerait-il s'il y avait des fichier dans le répertoire $repMenu ?

$ touch $repMenu/FichierA;select CHOIX in $(ls $repMenu); do echo "Votre Choix : $CHOIX. Le retour de select : $REPLY"; done



1) FichierA
2) Repertoire1
3) Repertoire2
4) Repertoire3
5) Repertoire4
#?

Cela l'ajoute à notre menu. Or nous ne voulons n'avoir que les répertoires. Il va donc falloir paufiner notre ls.

$ repMenu=$HOME/exploitation/Vinz/Menu;select CHOIX in $(ls -l $repMenu | grep ^d | awk '{print $9}'); do echo "Votre Choix : $CHOIX. Le retour de select : $REPLY"; done
1) Repertoire1

2) Repertoire2
3) Repertoire3
4) Repertoire4
#?
Il faut donc utiliser la version longue de ls (ls -l) qui affiche en premier caractère le type de fichier, en l'occurence pour les répertoire c'est le 'd' pour directory, et nous ne garderons donc que les lignes commençant par 'd' (grep ^d), et n'afficherons que la colonnes 9 (awk '{print $9}')

Voilà notre menu s'affiche donc correctement. une première étape, importante est franchie. Reste que si l'utilisateur choisi le choix 4, pour lister le Repertoire4, il.. quittera le menu. Bien oui puisque nous avions défini que pour $REPLY=4 nous sortirions par un exit 0 dans notre test case.

Il va donc falloir automatiser aussi la gestion du choix utilisateur.

Dans un premier temps nous ajouter un item fixe au menu. Pour cela c'est très simple, il suffit juste de modifier la variable PS3 du prompt du menu par :

PS3="
Q) Quitter

Quel répertoire voulez-vous lister : "



Maintenant interessons nous à la gestion de notre menu. Nous savons que si l'utilisateur entre une valeur $REPLY correspondant à un des items de select, la variable $item prendra la valeur l'item associé à $REPLY. Nous savons aussi, que si l'utilisateur entre une valeur $REPLY ne correspondant pas à un des items gérés par select, alors la variable $item sera nulle. Enfin nous voulons que si l'utilisateur entre pour valeur $REPLY 'Q' ou 'q' on quitte le programme.

Il faut bien faire une différence enter ce que nous savons et ce que nous voulons, cela rendra la gestion du menu plus facile.

D'abord modifions notre test case, avec ce que nous voulons, à savoir soit $REPLY vaut 'q' ou 'Q' et on quitte le programme, soit $REPLY vaut autre chose et nous appellerons une fonction menu_GestItem qui gèrera les items en fonction de ce que nous savons.

case "$REPLY" in



    q|Q)
        # On quitte le programme
        exit 0
        ;;
    *)
        # Appel de la fonction menu_GestItem
        menu_GestItem
        ;;

esac
Puis créons la fonction menu_GestItem :


function menu_GestItem {

    if [[ -z "$CHOIX" ]]                    # Si $CHOIX vaut Null
    then

      echo "Saisie invalide. \c"    # La saisie est incorrect
      read x

    else                                     # Sinon

        ls $repMenu/$CHOIX                 # On liste le contenu du répertoire choisi

    fi

}
Ce qui nous donne le script final suivant :


#!/bin/bash



################################
# CREATION DE MENU AUTOMATIQUE #

################################


####################
# VARIABLES        #
####################

repMenu=$HOME/Menu

####################
# FONCTIONS        #
####################

function menu_GestItem {



    if [[ -z "$CHOIX" ]] # Si $CHOIX vaut Null
    then

        echo "Saisie invalide. \c" # La saisie est incorrect
        read x
   
    else # Sinon

        ls $repMenu/$CHOIX # On liste le contenu du répertoire choisi


    fi


}

####################
# PROGRAMME PRINCIPAL #
####################



# Création du Menu listant les différents répertoires du dossier $HOME/Menu


PS3="

Q) Quitter
Quel répertoire voulez-vous lister : "


select $item in $(ls -l $repMenu | grep ^d | awk '{print $9}')
do

    case "$REPLY" in



        q|Q)
            # On quitte le programme
            exit 0
            ;;
        *)
            # Appel de la fonction menu_GestItem
            menu_GestItem
            ;;


esac

Voilà ce petit tutoriel est terminé, j'espère qu'il vous aura été utile et si vous avez la moindre remarque n'hésitez pas :)

Aucun commentaire:

Enregistrer un commentaire