Comment sortir d'un script bash avec menu et sous-menu

Résolu
Lume_56 Messages postés 46 Statut Membre -  
Lume_56 Messages postés 46 Statut Membre -

Bonsoir,

J'ai créé un script test simplifié ( il y a normalement 5 options) pour lancer des programmes avec un menu et sous-menu. L'installation se déroule normalement. Par contre, je ne peux pas sortir du programme et la fonction suivante ne peut pas d'exécuter.

Voici le script :

#!/bin/bash
# Essai de menu et sous-menu


# Sélection de l'archive oStorybook
PS3='Faites votre choix: '
options=("oStorybook" "Exit")
select opt in "${options[@]}"
do
    if [ "$opt" == "Exit" ] ; then
       echo "Au revoir !"
       break
    fi

    case $opt in
        "oStorybook")
         PS3='Quel choix ?'
    options=("jar" "sources"  "Quit")   
    select model in "${options[@]}"
    do         
         case $model in
            "jar")
                echo "l'archive jar va s'installer"
                wget $quiet1 -nv    http://download.tuxfamily.org/ostorybook/next/oStorybook.jar
                 break ;;                                                                  
            "sources")           
                echo "Installation des sources"
                wget $quiet1 -nv http://download.tuxfamily.org/ostorybook/next/oStorybook_src-5.05.08.zip     
                break;;
            "Quit")  
             exit
            ;;   
            #*) echo "invalid option $REPLY";;                      
        esac
    done             
       
    esac
done  

# Installation de nerd-dictation (pour poursuivre l'essai)
    echo ">> Installation de nerd-dictation"
    git clone https://github.com/ideasman42/nerd-dictation.git
   

Je reviens systématiquement sur :

Quel choix ?

Qui aurait une solution ? Merci à tous.

12 réponses

  1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     

    Bonjour,

    Peux-tu encore simplifier le code de sorte à ce qu'il soit minimal, et indiquer comment l'exécuter pour mettre en évidence ton problème (comportement attendu, comportement observé) ?

    Pas besoin de télécharger quoi que ce soit, juste la structure de menu, des echo aux bons endroits.

    Bonne chance

    0
  2. Lume_56 Messages postés 46 Statut Membre 1
     

    Bonsoir,

    Merci pour la rapidité apportée à ta réponse !

    Je te propose un script plus épuré.

    #!/bin/bash 
    # Essai de menu / sous-menu 
    
    # Sélection - je n'ai laissé que deux options, la première ayant un sous-menu
    PS3='Faites votre choix: '
    options=("Commandes" "Exit")
    select opt in "${options[@]}"
    do
    	if [ "$opt" == "Exit" ] ; then
        break
        fi
    
        case $opt in
            "Commandes")
             PS3='Quel choix ?'
    	options=("pwd" "curl" "Quit")   
    	select model in "${options[@]}" 
    	do 		
    		 case $model in
    			"pwd")
    				echo "pwd va s'afficher'"
    				 pwd
    				 break ;;
    				 				 					                             
    			"curl")           
    				echo "curl va s'afficher"
    				curl ifconfig.co/json    
    				break;; 
    			"Quit")  
    			 exit
    			;;   
    		*) echo "invalid option $REPLY";;                      
    		esac
    	done             
         exit   
        esac
    done  
    
    # afficher la date (autre commande pour vérifier la poursuite de l'installation) 
    	 
    	date +"Aujourd'hui, nous sommes le %A %d %B. Il est %T." 

    En fait, je désire effectuer un choix (enfin, deux !) , à deux niveaux différents :

    - le 1er niveau  (menu principal), entre les deux options "Commandes" et "Exit".

    - le second, une fois l'option "Commandes" choisie, un autre choix intervient  entre "pwd", "curl" et "quit".

    Mon objectif est de sélectionner "Commandes" puis "pwd" par ex. pour ensuite voir la commande suivante "date..." s'exécuter.

    Lors de l'exécution, le choix "Commandes" "pwd" indique bien le chemin (pwd) comme attendu. Par contre, le programme s'arrête sans exécuter la commande suivante "date...".

    Si je sélectionne "Exit" au démarrage, on sort du menu et le programme affiche la commande suivante "date..." (cf. ci-dessous)

    1) commandes
    2) Exit
    Faites votre choix: 2
    Aujourd'hui, nous sommes le jeudi 20 octobre. Il est 22:08:41. C'est le 293e jour de l'année.
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    
    

    Comme tu as pu le constater, je ne suis pas un pro qui ne maîtrise pas tout. Je me suis inspiré de ce que j'ai pu glaner ici et là.

    Merci.

    0
  3. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     

    Bonjour,

    Pardon pour ma réponse tardive je manque de temps en ce moment. En fait il y a un problème au niveau de la structure de ton algorithme, je t'écris le structure du code en python et te laisse l'adapter en bash.

    Code :

    #!/usr/bin/env python3
    
    import sys
    
    def select(choices):
        s = None
        while s not in choices:
            for choice in choices:
                print(choice)
            s = input("type your choice: ")
        return s
    
    def menu():
        while True:
            choice1 = select({"exit", "commande"})
            if choice1 == "exit":
                sys.exit(0)
            else:
                while True:
                    choice2 = select({"pwd", "curl", "quit"})
                    if choice2 == "pwd":
                        print("--> pwd")
                    elif choice2 == "curl":
                        print("--> curl")
                    elif choice2 == "quit":
                        break
    
    menu()

    break permet d'interrompre la boucle la plus enveloppante. Ici le premier break interrompt donc la première boucle while, et le deuxième break interrompt la 2e boucle while. Ainsi :

    • quand on choisit "exit" (première boucle) on interrompt la première boucle while et donc le programme ;
    • quand on fait "quit" (deuxième boucle), on interrompt la deuxième boucle et donc on refait un tour dans la première boucle while (ce qui revient à afficher le premier menu).

    J'ai de plus défini une fonction select afin que le programme redemande à l'utilisateur de faire son choix si celui-ci n'est pas conforme à l'ensemble des valeurs valides.

    Exécution :

    (mando@silk) (~) $ python3 toto.py 
    commande
    exit
    type your choice: commande
    quit
    pwd
    curl
    type your choice: pwd
    --> pwd
    quit
    pwd
    curl
    type your choice: plop
    quit
    pwd
    curl
    type your choice: curl
    --> curl
    quit
    pwd
    curl
    type your choice: quit
    commande
    exit
    type your choice: exit
    

    Bonne chance

    0
  4. Lume_56 Messages postés 46 Statut Membre 1
     

    Bonjour,

    Merci beaucoup d'avoir consacré une partie de ton temps à répondre à ma question. Je vais étudier le script en détail et l'adapter au mieux.

    Bonne journée.

    Cordialement.

    0
    1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
       

      Parfait, en fait je pense que dans ton cas, ligne 30, si tu remplaces exit par break ça devrait suffire (exit quitte le programme au lieu de quitter la boucle la plus enveloppante). Note par ailleurs que si tu veux suivre exactement le code que je t'ai donné, bash permet de déclarer des fonctions.

      Tu peux aussi adapter le script python que je t'ai donné à tes besoins, car c'est un langage bien plus confortable que le bash. Le bash prend surtout son sens quand on veut lancer des commandes plus compliquées.

      0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. Lume_56 Messages postés 46 Statut Membre 1
     

    Merci pour ces précisions. Je n'ai pas encore eu le temps de regarder attentivement !

    0
  7. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     

    Bonjour,

    J'ai trouvé le temps de regarder comment écrire ton script en bash, voici à quoi ça peut ressembler :

    #!/bin/bash
    # Define the menu list here
    PS3="> "
    select opt in "Commands" "Exit"
    do
        if [ "$opt" == "Exit" ] ; then
            echo "Exit"
            break
        fi
    
        PS3=">> "
        select subopt in "pwd" "curl" "Quit"
        do
            case "$subopt" in
                "Quit")
                    echo "Quit"
                    break
                    ;;
                "pwd")
                    echo "pwd"
                    ;;
                "curl")
                    echo "curl"
                    ;;
            esac
        done
    
        PS3="> "
    done

    Pour s'y retrouver, tu noteras que je change à la volée l'apparence de l'invite de commande :

    • > pour le menu principal
    • >> pour le sous menu

    Concernant le premier break : celui qui interrompt la boucle select opt. On arrive donc à la dernière ligne du programme et donc on quitte le script. Comme rien n'est fait après le menu, on aurait aussi pu écrire exit 0, ce qui quitte immédiatement le programme.

    Concernant le second break : celui qui interrompt la boucle select subopt. Si on voulait quitter le programme avec cette option, il faudrait le remplacer par exit 0.

    Exemple :

    1) Commands
    2) Exit
    > 1
    1) pwd
    2) curl
    3) Quit
    >> 1
    pwd
    >> 1
    pwd
    >> 2
    curl
    >> 3
    Quit
    > 2
    Exit

    Bonne chance

    0
  8. Lume_56 Messages postés 46 Statut Membre 1
     

    Merci pour ta démonstration très claire. La difficulté que je rencontre consiste à poursuivre l'exécution des commandes. Si tu regardes bien, je précisais dans mon premier message qu'après le choix effectué, l'exécution devait se poursuivre avec autre commande :

    # afficher la date (autre commande pour vérifier la poursuite de l'installation) 
    	 
    	date +"Aujourd'hui, nous sommes le %A %d %B. Il est %T." 

    C'est à ce niveau que le programme bloquait. Cette commande n'était lue qu'en cas de sortie de la partie du script traitant du choix. 

    1) Commands
    2) Exit
    > 2
    Exit
    Aujourd'hui, nous sommes le vendredi 28 octobre. Il est 12:55:44.
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

    J'ignore s'il est possible de traiter cette commande dans le script.

    0
  9. Lume_56 Messages postés 46 Statut Membre 1
     

    Bonjour,

    J'ai résolu la question en adaptant un script trouvé sur le Net proposant menu et sous-menu.  Voici une version simplifiée. Si elle peut être utile à certains néophytes comme moi, tant mieux !

    Encore merci.

    #!/bin/bash
    # Script avec menu et sous-menu
    while :
    do
    echo "
    ----- SELECT  -----
    
    (1)  A
    (2)  B
    (3)  Q = Quitter
    "
    
    read choix_
    case $choix  in
     1) echo " -----sous-menu 1-----
    
        1)  A1
        2)  A2
        3)  Q = Quitter
        "
        read choix sous-menu 1
        echo
        case $choix sous-menu 1 in
        1) echo "vous avez sélectionné A1 "
        commande A1 ;;
        2) echo "vous avez sélectionné A2 "
        commande A2;;
        3| Q | q ) echo ; exit 0 ;;
        *) echo "Erreur saisie sous-menu 1";;
        esac
        ;;
    
     2) echo " -----sous-menu 2-----
    
        1)  B1
        2)  B2
        3)  Q = Quitter
        "
        read choix sous-menu 2
        echo
        case $choix sous-menu 2 in
        1) echo "vous avez sélectionné B1 "
        commande B1;;
        2) echo "vous avez sélectionné B2 "
        commande B2;;
        3| Q | q ) echo ; exit 0 ;;
        *) echo "Erreur saisie sous-menu 2";;
        esac
        ;;
    
    3) | Q | q ) echo ; exit 0
    ;;
    
    *) echo "Erreur saisi menu principal"
    ;;
    	esac
    done
    0
  10. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     

    Bonjour,

    Concernant ton message #8, je n'ai pas compris : la commande date s'exécute quand tu rencontres la commande (au même titre que les echo que j'ai mis en exemple), mais j'imagine que tu as depuis contourné le problème. En tout cas l'idée est toujours la même que dans mon message #7 : la manière dont sont imbriqués les sous-menus est reflétée par la manière dont sont imbriqués les select.

    Voilà à quoi ça pourrait ressembler :

    #!/bin/bash
    # Define the menu list here
    PS3="> "
    select opt in "A" "B" "Exit"
    do
        case "$opt" in
        "Exit")
            echo "Exit"
            break
            ;;
        "A")
            PS3=">> "
            select subopt in "Quit" "A1" "A2"
            do
                case "$subopt" in
                    "Quit")
                        echo "Quit"
                        break
                        ;;
                    "A1")
                        echo "A1"
                        ;;
                    "A2")
                        echo "A2"
                        ;;
                esac
            done
            ;;
        "B")
            PS3=">> "
            select subopt in "Quit" "B1" "B2"
            do
                case "$subopt" in
                    "Quit")
                        echo "Quit"
                        break
                        ;;
                    "B1")
                        echo "B1"
                        ;;
                    "B2")
                        echo "B2"
                        ;;
                esac
            done
            ;;
    
        esac
        PS3="> "
    done
    

    Exécution :

    (mando@silk) (~) $ bash toto.sh 
    1) A
    2) B
    3) Exit
    > 1
    1) Quit
    2) A1
    3) A2
    A> 3
    A2
    A> 2
    A1
    A> 1
    Quit
    > 2
    1) Quit
    2) B1
    3) B2
    B> 2
    B1
    B> 3
    B2
    B> 1
    Quit
    > 3
    Exit

    Concernant ton message #9, c'est une manière plus basique de faire. Contrairement à celle que je viens de proposer; elle n'utilise pas select, donc elle s'applique à des shells autre que bash.

    Bonne chance

    0
  11. Lume_56 Messages postés 46 Statut Membre 1
     

    Merci. je comprends bien la structure du script. Par contre, je n'ai toujours pas compris comment ajouter une commande pour poursuivre le script une fois le choix effectué.

    Pour illustrer mon propos, voici ce qui a motivé mes messages :

    Je contribue au développement (porteur d'idées, testeur et accessoirement "codeur !)) de oStorybook.

    Ayant découvert un programme de Speech to text (nerd-dictation), j'ai proposé d'intégrer ce logiciel dans oStorybook, non pas pour écrire des livres "à la volée" mais pour faciliter la prise de notes, les remarques, etc. Une précision. Une fois lancé, ce programme tourne en tâche de fond et envoie les mots reconnus dans l'application qui est active (courrier, traitement de texte, console, etc)

    A l'occasion, je me suis attelé avec le développeur principal à la réalisation du script pour automatiser l'installation.

    Le script d'installation lit et exécute les différentes commandes : définition des répertoires d'installation, dépendances, etc. Viennent ensuite la choix de la langue et du modèle linguistique "léger" ou "complet". C'est cette phase qui me posait problème et que j'ai traitée d'une manière détournée (cf #8) avec car, une fois les choix effectués, le programme ne se poursuivait pas. D'où la simulation avec la commande "date" dans mes messages.

    Concrètement, j'ai ajouté la commande "whoami" à la fin de ton dernier script, après Exit. La sortie ne m'a pas étonné, la commande reste ignorée. C'est cette difficulté  sûrement très triviale que je voulais résoudre. Et comme je suis curieux de nature...

    J'ai finalement trouvé un moyen détourné pour réaliser le script qui fonctionne.

    Encore merci pour ta disponibilité.

    0
    1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
       

      Par contre, je n'ai toujours pas compris comment ajouter une commande pour poursuivre le script une fois le choix effectué.

      Peux-tu clarifier ? Si je reprends le message #10, si tu choisis Exit, comme maintenant j'ai mis un break (au lieu de exit), cela te fait poursuivre le programme ligne 51 (au lieu de quitter le script).

      Ayant découvert un programme de Speech to text (nerd-dictation), j'ai proposé d'intégrer ce logiciel dans oStorybook, non pas pour écrire des livres "à la volée" mais pour faciliter la prise de notes, les remarques, etc. Une précision. Une fois lancé, ce programme tourne en tâche de fond et envoie les mots reconnus dans l'application qui est active (courrier, traitement de texte, console, etc)

      Pourquoi pas, mais de tels outils existent déjà. Par exemple, dans les hôpitaux, certains docteurs ont une espèce de micro qui leur permettent de remplir les dossiers. Ils dictent également les ponctuations et les retours à la lignes, et font quelques corrections mineures au clavier. Cette page recense quelques outils analogues sous Linux. Peut-être qu'il vaut mieux consacrer son énergie à contribuer à un projet existant (pour l'améliorer) plutôt que re-développer quelque chose qui a déjà été fait, à bon entendeur ;-)

      Afin de consacrer un fil de discussion par sujet, si tu veux plus de détails, merci d'ouvrir un nouveau fil de discussion.

      Concrètement, j'ai ajouté la commande "whoami" à la fin de ton dernier script, après Exit. La sortie ne m'a pas étonné, la commande reste ignorée. C'est cette difficulté  sûrement très triviale que je voulais résoudre. Et comme je suis curieux de nature...

      Si tu as bien recopié le script #10 et ajouté ligne 51 la commande whoami, normalement ça fait ce que tu veux.

      1) A
      2) B
      3) Exit
      > 3
      Exit
      mando
      

      Si j'ai mal compris ce que tu veux faire, merci de clarifier.

      Bonne chance

      0
  12. Lume_56 Messages postés 46 Statut Membre 1
     

    Il ne s'agit nullement de ré-développer un programme existant mais de l'adapter, ce qui est bien différent. Le projet nerd-dictation est disponible sur Github. Combien d'utilisateurs de l'outil informatique connaissent ce site et combien seraient capables de récupérer l'archive, de l'installer, d'installer les dépendances et de configurer le fichier linguistique ? C'est ce que nous faisons actuellement pour proposer une fonctionnalité opérationnelle ne nécessitant aucune manipulation de la part des utilisateurs.

    C'est également ce qu'a fait Papoteur qui a écrit un GUI pour nerd-dictation, Elograf qui malheureusement ne fonctionne pas sur toutes les distros ( Ubuntu Mate en fait partie).

    0
    1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
       

      Ah très bien, je ne connaissais pas mais effectivement si c'est l'adapter, c'est parfait !

      Quelques pistes pour le packaging : le projet nerd-dictation dispose d'un setup.py, ce qui signifie que le paquet est plus ou moins prêt à être packagé sur Pypi (tous les OS), en rpm (distributions basées sur redhat) ou en deb (distributions basées sur debian). Si ton projet dépend de nerd-dictation et d'autres projets, tu peux tout à fait faire ton propre paquet avec ses propres dépendances. Pour plus de détails, voir ce tutoriel.

      0
  13. Lume_56 Messages postés 46 Statut Membre 1
     

    Merci pour ces pistes. Le packaging est à l'état de projet car il reste d'autres points à développer.

    0