IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Shell et commandes GNU Discussion :

Test -n et boucle while


Sujet :

Shell et commandes GNU

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut Test -n et boucle while
    Bonjour,

    Avec man test, je lis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
           -n STRING
                  the length of STRING is nonzero
     
           STRING equivalent to -n STRING
     
           -z STRING
                  the length of STRING is zero
    Donc si je fais -n sur une variable, je peux savoir si elle est non-vide (true) ou vide (false). Or, dans le code suivant, la méthode 2 provoque une boucle infinie que je n'arrive pas à m'expliquer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    !/bin/bash
     
    typeset LISTE="un deux trois quatre cinq"
    typeset ITEM=""
    typeset -i INDICE=1
     
    ITEM=$(echo $LISTE | cut -d' ' -f $INDICE)
     
    # METHODE UNE
    echo "Methode une"
     
    while true
    do
            echo "$INDICE = $ITEM"
            let INDICE=$INDICE+1
            ITEM=$(echo $LISTE | cut -d' ' -f $INDICE)
            if [ -z $ITEM ]
            then
                    break # Quitter le while true
            fi
    done
     
    # METHODE DEUX
    echo
    echo
    echo "Methode deux"
     
    let INDICE=1
     
    ITEM=$(echo $LISTE | cut -d' ' -f $INDICE)
     
    while [ -n $ITEM ]
    do
            echo "$INDICE = $ITEM"
            let INDICE=$INDICE+1
            ITEM=$(echo $LISTE | cut -d' ' -f $INDICE)
    done
    Merci d'avance pour vos lumières

  2. #2
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 651
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 651
    Par défaut
    de l'importance de "quoter" les expressions à tester !

    le problème n'existe pas avec les crochets doubles.
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  3. #3
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Après avoir posté, j'ai pensé aux doubles crochets, et j'avais essayé et ça marchait. Bien vu.

    Des fois, je trouve le comportement de bash imprévisible. Le script suivant marche très bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #!/bin/bash
     
    typeset LISTE="un deux trois quatre cinq"
    typeset ITEM=""
    typeset -i INDICE=1
     
    ITEM=$(echo $LISTE | cut -d' ' -f $INDICE)
     
    let INDICE=1
     
    ITEM=$(echo $LISTE | cut -d' ' -f $INDICE)
     
    while [ $INDICE -le 10 ] 
    do
            echo "$INDICE = $ITEM"
            let INDICE=$INDICE+1
            ITEM=$(echo $LISTE | cut -d' ' -f $INDICE)
    done
    C'est le même genre de test pourtant... Toutes les pages que j'ai vu sur le net (quant à while dans bash) utilisent des crochets simples sauf si tests multiples avec && ou ||.

    Il y a t-il une documentation précise sur le comportement de [[ ]] face à [ ] ?

    EDIT : ah je viens de comprendre ta remarque des quotes : while test -n "$ITEM" marche très bien. Je viens de trouver ce thread où c'est assez bien expliqué pour ceux que ça intéresse.

    EDIT 2 : je viens de voir le message de Sve@r ^^
    Merci pour les précisions sur les quotes, les conséquences (qui complètent et vont bien bien plus loin que mon lien). Merci aussi pour les noms des variables.

    Je vais placer le sujet comme résolu du coup, je pense avoir eu assez d'infos. Merci à tous les deux.

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Des fois, je trouve le comportement de bash imprévisible. Le script suivant marche très bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #!/bin/bash
     
    typeset LISTE="un deux trois quatre cinq"
    typeset ITEM=""
    typeset -i INDICE=1
     
    ITEM=$(echo $LISTE | cut -d' ' -f $INDICE)
     
    let INDICE=1
     
    ITEM=$(echo $LISTE | cut -d' ' -f $INDICE)
     
    while [ $INDICE -le 10 ] 
    do
            echo "$INDICE = $ITEM"
            let INDICE=$INDICE+1
            ITEM=$(echo $LISTE | cut -d' ' -f $INDICE)
    done
    C'est le même genre de test pourtant...
    ... pourtant pas tout à fait. Déjà INDICE n'est jamais vide alors que le pb initial venait de la vision qu'avait le shell d'une variable vide...

    Citation Envoyé par Bktero Voir le message
    Toutes les pages que j'ai vu sur le net (quant à while dans bash) utilisent des crochets simples sauf si tests multiples avec && ou ||.
    Attention, && et || ne sont pas des connecteurs internes à test mais des connecteurs du shell. Ils servent donc à connecter des commandes différentes entre elles style rm -f /etc/passwd || echo "effacement impossible" (j'espère que tu bosses pas en root )
    Pour les connecteurs internes test faut utiliser "-a" et/ou "-o"
    Exemple: année bissextile ou pas
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    year=$(date '+%Y')
    test \( $(expr $year % 4) -eq 0 -a $(expr $year % 100) -ne 0 \) -o $(expr $year % 400) -eq 0

    Accessoirement il n'y a pas d'optimisation de l'évaluation. Donc même si l'évaluation est fixée dès le départ, le test fera toute l'expression
    Démo
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    rm -f /tmp/a
    test -d . -o -n "$(touch /tmp/a)" && echo "ok"
    ls -l /tmp/a
    Bien que "." soit un répertoire et que le test soit définitivement vrai dès cet instant, le fichier /tmp/a est quand-même créé...

    Citation Envoyé par Bktero Voir le message
    Il y a t-il une documentation précise sur le comportement de [[ ]] face à [ ] ?


    EDIT : ah je viens de comprendre ta remarque des quotes : while test -n "$ITEM" marche très bien. Je viens de trouver ce thread où c'est assez bien expliqué pour ceux que ça intéresse.
    Pendant que tu éditais moi j'ai trouvé celui-là http://abs.traduc.org/abs-5.0-fr/ch07.html#dblbrackets...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 102
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Attention, && et || ne sont pas des connecteurs internes à test mais des connecteurs du shell.
    Justement, c'est bien une source de confusion!
    && et || sont bien des connecteurs internes à [[..]] !!!
    (en plus d'être des connecteurs du shell!)

    Les commandes suivantes donnent le même résultat:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    test 3 -gt 2 && test 4 -gt 3
    test 3 -gt 2 -a 4 -gt 3
    [ 3 -gt 2 -a 4 -gt 3 ]
    [[ 3 -gt 2 && 4 -gt 3 ]]

  6. #6
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par jack-ft Voir le message
    Justement, c'est bien une source de confusion!
    && et || sont bien des connecteurs internes à [[..]] !!!
    (en plus d'être des connecteurs du shell!)
    D'autant plus source de confusion que j'ai l'habitude (de par mon travail sur multiplateformes) d'associer "shell" à "Bourne Shell" alors que là, tu associes "shell" à "bash" (normal vu que c'est le shell par défaut sous Linux)

    Citation Envoyé par jack-ft Voir le message
    Les commandes suivantes donnent le même résultat:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    test 3 -gt 2 && test 4 -gt 3
    test 3 -gt 2 -a 4 -gt 3
    [ 3 -gt 2 -a 4 -gt 3 ]
    [[ 3 -gt 2 && 4 -gt 3 ]]
    La 3° n'étant qu'un alias de la seconde, et la 4° étant spécifique à bash (que je ne maitrise pas assez), je vais les éliminer des commandes à regarder. Donc voici juste les 2 premières mais rendues systématiquement fausses
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    test 3 -lt 2 && test 4 -lt 3
    test 3 -lt 2 -a 4 -lt 3
    Hé bien la première n'effectuera qu'une seule comparaison (puisque 2 commandes à suivre mais la seconde n'étant pas exécutée du fait que la première renvoie un état "faux") alors que la seconde fera toute l'évaluation même inutile.
    Donc même résultat "visible" mais pas le même résultat au niveau du proc...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Bonjour,

    Avec man test, je lis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
           -n STRING
                  the length of STRING is nonzero
     
           STRING equivalent to -n STRING
     
           -z STRING
                  the length of STRING is zero
    Donc si je fais -n sur une variable, je peux savoir si elle est non-vide (true) ou vide (false). Or, dans le code suivant, la méthode 2 provoque une boucle infinie que je n'arrive pas à m'expliquer :
    Salut N_Bah t'a fait un résumé. Je vais détailler un peu
    Lorsque ITEM est vide, l'instruction test -n $ITEM est traduite en test -n. Or (et ça je ne sais pas si c'est voulu ou si c'est un bug de la commande test) dans ce cas là ça renvoie "vrai". Parce que, comme c'est écrit dans le man, test -n demande une chaine à évaluer et là il n'y en a plus.
    Tu auras un problème analogues mais plus explicites si tu écris un truc de ce genre
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    while true
    do
        echo "Voulez-vous sortir (o/n) ?"
        read rep
        test $rep = o && break
    done
    Si tu tapes "return" à la question, tu auras un truc du style "test := unary operator expected" signifiant que le shell, ayant lu test = o avec un seul opérande, demande alors un opérateur unaire et non binaire.

    Donc pour pallier ce problème qu'on retrouve à plusieurs niveaux, on encadre toujours les chaines (et les variables stockant des chaines) de quottes doubles
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    while true
    do
        echo "Voulez-vous sortir (o/n) ?"
        read rep
        test "$rep" = "o" && break
    done
    Ainsi, même une chaine vide laissera une présence à gauche de l'opérateur.

    Accessoirement encadrer systématiquement les variables de quottes élimine d'autres soucis comme le fait d'avoir des espaces dans la chaine surtout quand la variable est ensuite passée à un outil qui se cale sur l'espace pour travailler comme le "for"...

    PS: Les variables sont généralement écrites en minuscules pour ne pas créer de collision avec les variables prédéfinies qui sont, elles, écrites en majuscules...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [MySQL] Boucle while et test de presence d'un utilisateur
    Par baffreux dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 23/04/2015, 15h08
  2. [MySQL] Table html avec boucle test if dans un while
    Par dancom5 dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 23/11/2011, 18h27
  3. Aide test d'entrée boucle while
    Par xmc_boss dans le forum Shell et commandes GNU
    Réponses: 2
    Dernier message: 21/05/2008, 23h01
  4. [Conception] Problème de test dans une boucle while
    Par Cyrius dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 26/11/2005, 18h07
  5. [débutant]Documentation? boucle "while"? Session?
    Par o151181 dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 19/01/2004, 15h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo