Forum Programmation.shell Passer de paramètres à valeurs saisie par l'utilisateur..

Posté par . Licence CC by-sa.
Tags : aucun
0
27
oct.
2018

Bonsoir à tous,
Tout fraîchement inscrit sur ce forum, je sollicite déjà votre aide.. Après avoir chercher pas mal de temps et arpenter plusieurs forums, je ne parviens pas à trouver une solution.
Voilà ma situation:

J'ai crée un script qui affiche la valeur minimum parmis des valeurs passées en paramètre.

#!/bin/sh
nb=$1
while [ $# -ne 0 ]
do
    if [ $1 -lt $nb ]
    then
    nb=$1
    shift
    else
    nb=$nb
    shift
    fi
done
echo "Le nombre le plus petit des paramètres est $nb"

Seulement voilà, j'aimerais le modifier pour que ces valeurs ne soit plus passer en paramètre mais saisie par l'utilisateur. J'avais penser à la manière suivante:

  • read var
  • Une boucle for dont i va prendre chaque valeur de var et avec à l'interieur un if qui testera si i est inférieur au terme précédant, avec le code suivant:
#!/bin/sh 
read var
nb=99999999
for i in $var
do
    if [ $i -lt $nb ]
    nb=$i
    else
    nb=$nb
    fi
done
echo " La valeur la plus petite est $nb"

Seulement je suis obliger d'initialiser la variable nb à un très grand nombre.. ce qui est problématique.

Si vous avez une solution je suis preneur :)

Merci d'avance!

  • # modifie l'initialisation

    Posté par . Évalué à 3.

    Au lieu de d'initialiser nb manuellement
    initialise le avec le premier nombre de ta liste saisie par l'utilisateur.

    De plus il manque une instruction dans ta structure de contrôle.

    Je te laisse chercher laquelle c'est plus formateur :D

    • [^] # Re: modifie l'initialisation

      Posté par . Évalué à 6.

      Au lieu de d'initialiser nb manuellement
      initialise le avec le premier nombre de ta liste saisie par l'utilisateur.

      Quelle est ta manière simple de récupérer juste le premier élément malgré bash (je dis « malgré », parce que bash, c’est comme Perl en moins puissant mais plus compliqué, même s’il est bien moins indigent que le Bourne shell dont il descend) ?

      Parce que je vois l’affectation de toute la liste aux variables $1, $2… avec

      set -- $var

      (intérêt supplémentaire : on peut ensuite reprendre le script prévu pour traiter les arguments), l’affectation de toute la liste à un tableau avec

      $tab=($var)

      (ensuite ${tab[2]} pour accéder par exemple au troisième élément, $tab donnant le premier élément), mais récupérer juste le premier élément, je ne vois pas trop…

      À la réflexion, on peut récupérer juste le premier élément avec

      ${var%% *}

      Un peu cryptique quand même pour un débutant (enfin c’est du bash…) ; explication : c’est une substitution qui rend le contenu de la variable allégé du premier espace et de tout ce qui suit.

      De plus il manque une instruction dans ta structure de contrôle.

      Effectivement.
      Par contre, il y a aussi des instructions superflues : nb=$nb, on peut aussi sortir le shift du if then else fi dans le premier script et supprimer le else dans la foulée.

      Tant qu’on y est, on peut utiliser && plutôt que if then fi et le contenu de la boucle while (du premier script) se réduit à :

      do
          [ $1 -lt $nb ] && nb=$1
          shift
      done

      ¯ : macron (typographie), petit signe diacritique, qui prétend ne pencher ni à gauche ni à droite, mais se place nettement au dessus des vraies lettres, qu’il considère avec mépris.

      • [^] # sh

        Posté par . Évalué à 5.

        Ah, je viens de remarquer que le shell utilisé est sh (#!/bin/sh). Du coup, à moins que ce soit bash quand même (c’est le cas sur certaines distributions), pas de tableau.

        Les autres solutions doivent fonctionner quand même avec la plupart des sh (/bin/sh n’est pas le même shell suivant la distribution ou le système). Peut-être pas avec le plus indigent (parmi ceux que je connais, celui d’OpenIndiana : un vieux ksh notoirement bogué et en deçà des spécifications POSIX, conservé pour ne pas casser des scripts qui comptent sur son comportement).

        Le seul intérêt (mais réel) d’utiliser sh est la portabilité, dans le sens où tout système de type Unix aura un /bin/sh, alors qu’il aura peut-être ksh mais pas bash ou l’inverse. C’est dommage, dans la mesure où les fonctionnalités communes aux shells évolués disponibles sur chaque système sont plus importantes que celles de leurs /bin/sh, mais il n’y a pas de chemin commun pour ces shells évolués.

        Pour ma part, dans un environnement que je maîtrise, je fais directement du Perl. Ça m’évite de mauvaises surprises quand les besoins augmentent. Par exemple, dans l’exemple actuel, on se retrouve finalement à devoir traiter des nombres décimaux et on s’aperçoit alors que le shell ne gère que les entiers…

        ¯ : macron (typographie), petit signe diacritique, qui prétend ne pencher ni à gauche ni à droite, mais se place nettement au dessus des vraies lettres, qu’il considère avec mépris.

      • [^] # Re: modifie l'initialisation

        Posté par . Évalué à 2.

        bash pu pas bash

        ça change pas grand chose la saisie est une chaîne de caractère donc il faut découpé la chaîne. les éléments sont séparé par des espaces donc il faut utiliser les utilitaire pour traiter les chaînes.

        donc des utilitaires comme tr cut, sed, etc.

        en faisant par exemple :
        nb=$( echo "$var" | cut -d' ' -f1 )

        en supposant que le premier caractère n'est pas un espace (mais si c'en ai un il suffit de le supprimer avec tr par exemple). et pour un vieux système comme solaris ou hpux par exemple tu utilises des anti-quotes `.

        Les utilitaires comme cut tr et sed sont souvent plus rapide à utiliser que les substitutions.

        Juste remarque en passant le shell au départ est conçu pour servir de glu aux utilitaires unix.

        Sinon d3f4lt semble satisfait de son premier programme qui ne gère que des entiers son problème est d'utiliser une saisie interactive de tous les nombres au début.

        Donc je ne réponds dans ce post qu'a ses deux questions :

        Comment faire la saisie par l'utilisateur de la suite d'entiers au début du programme ( réponse qu'il a trouvée lui même ).

        Et je réponds à sa deuxième interrogation qui est comment éviter d'avoir à initialiser (certe implicite ) nb avec un très grand nombre.

        Niveau cryptique ta réponse l'est encore plus sachant
        sur la fin ta réponse ( fin de second message )c'est : moi je le fait en perl

        C'est un peu hors sujet non ?
        peux-tu m'expliquer quelle est ta solution concrète dans ce cas ?

        • [^] # Re: modifie l'initialisation

          Posté par . Évalué à 5. Dernière modification le 28/10/18 à 11:04.

          ça change pas grand chose la saisie est une chaîne de caractère donc il faut découpé la chaîne. les éléments sont séparé par des espaces donc il faut utiliser les utilitaire pour traiter les chaînes.

          Bien compliqué pour séparer des chaines :

          $ var="a b c"
          $ for i in $var
          > do
          > echo $i
          > done
          a
          b
          c
          $ var="a b c"
          $ set $var
          $ echo $1
          a
          $ echo $2
          b
          $ echo $3
          c
          $ echo $*
          a b c
          $ echo $@
          a b c
          $ shift
          $ echo $1
          b
          $ echo $2
          c
          $ echo $3
          
          $ echo $*
          b c
          $ echo $@
          b c
          $

          Les utilitaires comme cut tr et sed sont souvent plus rapide à utiliser que les substitutions.

          Hein ? Les substitutions sont internes au shell alors que les utilitaires sont des appels à des programmes externes, donc nécessitent au moins un fork + exec (et charger la commande du disque vers la mémoire si elle n'y est pas déjà).

          • [^] # Re: modifie l'initialisation

            Posté par . Évalué à 2.

            C'est pas séparer des chaînes mais sélectionner le premier élément.

            et quand je dis plus rapide c'est pas au sens système mais au sens utilisateur concept de flux plus rapide à saisir et à mettre en œuvre.

            c'est vrai que dans ce cas la méthode fonctionne mais elle a des limites par exemple il est impossible d'ajouter des paramètre par la suite si le script évolue.

        • [^] # Re: modifie l'initialisation

          Posté par . Évalué à 3.

          bash pu pas bash

          Lapin compris.

          en faisant par exemple :
          nb=$( echo "$var" | cut -d' ' -f1 )

          C’est suffisamment peu trivial pour mériter d’être explicité à un débutant.
          Tu sembles avoir pris ma question pour une critique contre toi, mais c’était une vraie question. J’aurais pour louper un moyen simple d’obtenir le premier élément.

          S’il n’y en a pas (tu m’excuseras, j’espère, de ne pas considérer comme simple l’appel à des commandes tierces), c’est par contre encore une tare du shell POSIX.
          Bash, lui, supporte de vrais tableaux ; malheureusement, il n’est pas partout (même s’il est sur la plupart des distributions Linux, hormis les mini-distributions basées sur Busybox).

          et pour un vieux système comme solaris ou hpux par exemple tu utilises des anti-quotes `.

          Si on choisit /bin/sh pour la portabilité et qu’on n’est pas sûr de ne pas tomber sur un vieux shell, mieux vaut éviter autant que possible tous les « ajouts modernes », donc utiliser des anti-quotes.

          sur la fin ta réponse ( fin de second message )c'est : moi je le fait en perl
          C'est un peu hors sujet non ?

          Je n’ai pas dit le contraire ; c’est une digression qui ne s’adresse pas particulièrement à l’auteur de la question, dont je présume que le but est de se familiariser avec le shell. C’est pour ça que je n’ai pas développé.

          En shell, tu passes ton temps à essayer d’éviter des écueils (par exemple, les variables interprétées à chaque appel ; si elles peuvent contenir des espaces ou des caractères bizarres, tu as intérêt à les quoter correctement ; je connais un sysadmin pourtant expérimenté qui a effacé un tas de fichiers qu’il n’aurait pas dû à cause de ça) et à contourner les limitations (par exemple, les fonctions ne peuvent pas retourner de valeur hormis un code d’erreur).

          peux-tu m'expliquer quelle est ta solution concrète dans ce cas ?

          Si tu la veux, la voilà :

          #!/usr/bin/perl -w
          use strict;
          
          my @nb = @ARGV;
          if (! @nb)
          # En contexte scalaire, @nb rend le nombre d’éléments du tableau @nb.
          # On peut même l’utiliser comme booléen.
          {
              print "Nombres (séparés par des espaces : ";
              @nb = split ' ', <STDIN>;
          }
          @nb or die "Recherche du minimum ; il faut indiquer des nombres !\n";
          
          my $min = shift @nb;
          foreach (@nb) {
              $_ < $min and $min = $_;
          }
          
          print "Minimum : $min\n";

          et tant qu’on y est, l’équivalent en shell (pas tout à fait : la version Perl supporte des nombres décimaux) :

          #!/bin/sh
          
          if [ $# = 0 ]; then
              echo -n "Nombres (séparés par des espaces) : "
              read nbs
              set -- $nbs
          fi
          
          if [ $# = 0 ]; then
             echo "Recherche du minimum ; il faut indiquer des nombres !\n"
             exit
          fi
          
          min=$1
          while [ $# -gt 0 ]; do
              [ $1 -lt $min ] && min=$1
              shift
          done
          
          echo "Minimun : $min"

          Bon, dans le cas présent, la version shell n’est pas tellement plus compliquée, mais on est dans un cas simple : pas de valeurs pouvant contenir des espaces, pas besoin de plus d’un tableau…

          ¯ : macron (typographie), petit signe diacritique, qui prétend ne pencher ni à gauche ni à droite, mais se place nettement au dessus des vraies lettres, qu’il considère avec mépris.

          • [^] # Re: modifie l'initialisation

            Posté par . Évalué à 1.

            bash pu pas bash
            
            Lapin compris. avec l'accent Québécois je présume 
            

            Écrivant sur un clavier azerty à ce moment là mon doit a glissé et le O s'est transformé en P.
            Il fallait donc comprendre : bash ou pas bash

            et Gandalf m'a interdit de le modifier à posteriori

            en faisant par exemple :
            nb=$( echo "$var" | cut -d' ' -f1 )
            
            C’est suffisamment peu trivial pour mériter d’être explicité à un débutant.
            ```C'est une solution fonctionnelle à charge de celui qui reçois l'information de faire des tests pour s'approprier ce fonctionnement.
            

            Rappel : sont disponibles dans les distributions gnu/linux des outils comme man et info pour connaître les options des commandes et au pire pour cut par exemple cut --help.

            Tu sembles avoir pris ma question pour une critique contre toi, mais c’était une vraie question. J’aurais pour louper un moyen simple d’obtenir le premier élément.

            Non ce n'est pas ça, mais la question était clair et circonscrite et ta réponse longue un peu touffue avec des digressions et parfois du hors sujet. :) de plus le bash bashing :) tout le long de tes propos m'a un peu irrité.
            J'ai toujours entendu dire : "il n'y a pas de mauvais langage, il n'y a que des mauvais développeurs" et je m'applique cette maxime chaque jours surtout quand j'écris un bug dans un programme.

            S’il n’y en a pas (tu m’excuseras, j’espère, de ne pas considérer comme simple l’appel à des commandes tierces), c’est par contre encore une tare du shell POSIX.
            

            J'aime beaucoup cette assertion mais elle est infondée le shell à justement été conçu comme un environnement permettant d'utiliser des commandes externes très performantes dans ce qu'elle font c'est la philosophie même du shell être la glu entre diverses commande Unix et c'est sa grande force.

            petit article wikipedia https://fr.wikipedia.org/wiki/Shell_Unix

            En lisant les livres de Christophe Blaess c'est une chose claire également :

            Langages de scripts sous Linux https://www.blaess.fr/christophe/livres/scripts-sous-linux/ celui-ci est épuisé mais ce trouve en occasion.
            Scripts shell Linux et Unix https://www.blaess.fr/christophe/livres/scripts-shell-linux-et-unix/

            Bash, lui, supporte de vrais tableaux ; malheureusement, il n’est pas partout (même s’il est sur la plupart des distributions Linux, hormis les mini-distributions basées sur Busybox).
            

            c'est pour celà que quand on fait un script shell il faut tenir compte du contexte. De plus souvent une simple chaîne de caractères suffit pour les usages courants.

            et pour un vieux système comme solaris ou hpux par exemple tu utilises des anti-quotes `.
            
            Si on choisit /bin/sh pour la portabilité et qu’on n’est pas sûr de ne pas tomber sur un vieux shell, mieux vaut éviter autant que possible tous les « ajouts modernes », donc utiliser des anti-quotes.
            

            Je ne suis pas d'accord avec cette analyse comme la personne qui pose une question est "débutante" elle a pu très bien lire des documentations ou on indique #!/bin/sh sans vraiment noter la signification réelle de cette ligne ou se poser la question.
            J'ai croisé un administrateur système débutant deux années d'expérience qui n'écrivait pas de shebang dans ses scripts, et après discussion m'a avoué qu'il ignorait ce détail mais don't act maintenant il l'a appris et ses script n'en sont que meilleurs.

            Et personnellement je suis favorable à l'utilisation des fonctionnalités plus récentes disponible que de garder les vielles habitudes ( ce n'ai que mon opinion ).

            mais il est important de connaître les anciennes syntaxe pour ne pas être surpris lors de la relecture d'un script.

            sur la fin ta réponse ( fin de second message )c'est : moi je le fait en perl
            C'est un peu hors sujet non ?

            Je n’ai pas dit le contraire ; c’est une digression qui ne s’adresse pas particulièrement à l’auteur de la question, dont je présume que le but est de se familiariser avec le shell. C’est pour ça que je n’ai pas développé.

            Cette partie du site est un forum son but est de répondre aux questions.Mais pour les digressions pourquoi ne pas rédiger un journal pour s'adresser à un public plus large ?

            Et je suis prêt et heureux d'en discuter avec toi pour une rédaction conjointe si tu le souhaites.

            En shell, tu passes ton temps à essayer d’éviter des écueils (par exemple, les variables interprétées à chaque appel ; si elles peuvent contenir des espaces ou des caractères bizarres, tu as intérêt à les "quoter" correctement ; je connais un sysadmin pourtant expérimenté qui a effacé un tas de fichiers qu’il n’aurait pas dû à cause de ça) et à contourner les limitations (par exemple, les fonctions ne peuvent pas retourner de valeur hormis un code d’erreur).
            

            en utilisant les bonnes pratiques en "quotant" systématiquement tes variables tu n'as pas de problème dans 99,9% des cas.

            Tu avance ici un élément faux quand tu dis que les fonctions ne renvoient rien d'autre que des code retour.
            tu peux très bien leur faire renvoyer ce que tu veux sur la sortie standard.
            fais ce petit test ci-dessous.

            mafonction () {
            
            local var1="$1"
            local var2="$2"
            
            if [ ! -z "$1" -a ! -z "$2" ] 
            then
            
            echo "vos variable : $1 et $2 "
            
            return 0
            
            fi
            
            echo " erreur " 
            
            return 1
            
            }
            
            
            
            mafonction argument1 argument2
            
            echo $?
            
            mafonction argument1
            
            echo $?
            

            tu peux affecter ce retour à une variable comme ceci par exemple.
            ```
            mavar=$( mafonction argument1 argument2 )

            echo "$mavar"
            ```comme je te l'ai dit plus haut, je suis ouvert à toute suggestion pour l'écriture d'un journal ou d'une dépêche sur le sujet.

            Et pour finir sur une note positive je trouve ta solution en shell fort élégante et robuste :D

            Je regrette encore d'avoir été un peu sec dans ma réponse et j'espère que tu en comprendras la raison.

    • [^] # Re: modifie l'initialisation

      Posté par . Évalué à 1. Dernière modification le 28/10/18 à 16:40.

      Bonjour @Nodeus,

      Merci pour ta réponse, malheureusement après avoir lu les autres réponses j'ai fini par trouver la réponse sans vraiment avoir encore approfondi. Mais je n'aurais jamais trouver "set" seul :)

      Je regarde pour l'instruction dans ma structure de contrôle et je reviens vers toi quand j'aurais refait mon script :)


      Bonjour @totof2000,

      Merci pour ta réponse, la commande "set" est exactement celle que je cherchais pour compléter mon script. En effet, je voulais donner la première valeur de var à ma variable nb plutôt que de lui affecter obligatoirement un très grand nombre. Merci encore. :)

  • # pourquoi s'embeter

    Posté par . Évalué à 2.

    pourquoi faire une boucle de 1 à nb=99999
    alors qu'il suffirait d'ajouter un read dans ta boucle "while"

    while [ $var ne 'quit' ]
    do
      echo "saisir votre valeur"
      read $var
    
    ...
    
    done

    le script quittera quand l'utilisateur va saisir "quit"

    • [^] # Re: pourquoi s'embeter

      Posté par . Évalué à 1.

      Il me semble que d3f4lt veux que la suite soit saisie par l'utilisateur au début du programme dans son ensemble.
      sans avoir d'autre saisie qu'un retour à la ligne pour valider

      • [^] # Re: pourquoi s'embeter

        Posté par . Évalué à 2.

        justement non,
        dans son premier exemple, la liste est saisie des le lancement, en parametre au script

        et il veut desormais que ce soit saisie au fur et à mesure

        j'aimerais le modifier pour que ces valeurs ne soit plus passer en paramètre mais saisie par l'utilisateur

        donc c'est bien une saisie DANS la boucle qu'il faut faire

    • [^] # Re: pourquoi s'embeter

      Posté par . Évalué à 1.

      Bonjour @NeoX,

      Merci pour la modification, je vais tester ça de suite et prendre le plus intéressant pour moi. :)

      • [^] # Re: pourquoi s'embeter

        Posté par . Évalué à 2.

        et prendre le plus intéressant pour moi. :)

        il te faut surtout comprendre les differences entre les codes,
        pour pouvoir reutiliser cette connaissance dans des programmes plus complexes ensuite

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.