ce sujet est une digression de : ce script qui n'en fait qu'à sa tête où la question de l'existence d'une variable a été soulevée.
:
...Envoyé par jack-ft
Envoyé par NBaH
![]()
ce sujet est une digression de : ce script qui n'en fait qu'à sa tête où la question de l'existence d'une variable a été soulevée.
:
...Envoyé par jack-ft
Envoyé par NBaH
![]()
Envoyé par jack-ft
Généralement pas indispensable, effectivement.Envoyé par N_BaH
Mais je n'aime pas laisser à l'implémentation (ou aux spécifications) du langage la responsabilité d'initialiser les variables.
Un débutant ne sait pas toujours quelle est la valeur par défaut d'une variable qui n'est pas explicitement initialisée.
Du coup, lorsqu'un débutant lit du code (non pondu par lui) où une variable est explicitement initialisée (même à ce qui serait sa valeur par défaut si elle n'était pas initialisée), je trouve que c'est plus clair pour lui.
Sans compter les prudents (dont j'ai pu faire partie...):
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 % cat ./test.sh #!/bin/bash if test "$a" = ""; then echo "a vide (ou non initialisée)"; else echo "a pas vide"; fi set -u if test "$a" = ""; then echo "a vide (ou non initialisée)"; else echo "a pas vide"; fi % ./test.sh a vide (ou non initialisée) ./test.sh: line 4: a: unbound variable
Bien fait ! T'avais qu'à initialiser ta variable !
Attention! Le set -u n'est pas nécessairement du masochisme volontaire !
J'ai eu vu des environnements où les scripts étaient lancés avec des trucs comme bash -u ou où les .profile imposaient le set -u...
Déjà en shell la question ne se pose même pas: une variable qui n'est pas initialisée n'existe tout simplement pas (et donc elle n'a même pas de valeur par défaut). C'est d'ailleurs pour ça qu'on écrit toujours des guillemets quand on compare une variable avec une chaine (ex [ "$str" = "toto" ]) => au cas où $str n'existerait pas.
Et pour les langages qui acceptent des variables sans initialisation (ex le C) alors ça n'a pas vraiment d'importance non plus grace au principe de précaution qui est de ne jamais lire une variable qui n'a pas été préalablement remplie. Si on applique ce principe, on n'aura aucun souci quelle que soit la politique d'initialisation par défaut du langage (et on n'a même pas besoin de la connaitre)
Ca rassure en effet de savoir qu'une variable sera toujours créée avant d'être utilisée (en plus ça rejoint le principe de précaution dont j'ai parlé)![]()
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]
Bonjour
M'sieur ! M'sieur ! pourquoi vous dites "bien fait" ? Regardez mon écran. Tout marche bien.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 $ a=7 ./test.sh a pas vide a pas videJe me crispe. Une variable peut être testée sans être initialisée. Donc elle existe.une variable qui n'est pas initialisée n'existe tout simplement pas
Pas au cas où elle n'existerait pas, mais au cas où elle serait vide. Elle peut être initialisée et être devenue vide. Cas inverse du précédent.au cas où $str n'existerait pas.
Mais non ! C'est faux ! J'ai des scripts avec des modes cachés que j'active avec la technique montrée ci-dessus. Et je teste des variables jamais créées par défaut. Et le comportement du script change en fonction de variables inconnues auxquelles je fixe des valeurs connues de moi seul.Ca rassure en effet de savoir qu'une variable sera toujours créée avant d'être utilisée
Non. Tester (de même qu'afficher) une variable qui n'existe pas fonctionne (pour peu que le test soit correctement écrit)... mais ne la fait pas exister pour autant (d'ailleurs si cela la faisait exister je ne vois pas à quoi servirait l'option set -u).
D'ailleurs le shell fait bien la différence entre "ne pas exister/exister à vide/exister à non vide" car il y a ${var-texte} (qui renvoie "$var" si celle-ci existe ; et sinon renvoie le texte "texte") et ${var:-texte} (qui renvoie "$var" si celle-ci existe et qu'elle est non vide ; et sinon renvoie le texte "texte")
Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 $ maVariable=123 $ set |grep maVariable maVariable=123 # Là elle existe $ echo "${maVariable:-toto}" 123 $ unset maVariable $ set |grep maVariable $ # Là elle n'existe plus $ echo "${maVariable:-toto}" toto $ [ -z "$mavariable" ] && echo "le test se fait bien" le test se fait bien $ set |grep maVariable $ # Elle n'existe toujours pas
Non, je dis bien "si la variable n'existe pas". On peut tester une variable inexistante, encore une fois si on veille bien à positionner des éléments permettant de ne pas avoir de test bancal
Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 $ maVariable=toto $ set |grep maVariable maVariable=toto $ test $maVariable = toto && echo "oui toto" || echo "non toto" oui toto $ unset maVariable $ test $maVariable = toto && echo "oui toto" || echo "non toto" bash: test: = : opérateur unaire attendu non toto $ test _$maVariable = _toto && echo "oui toto" || echo "non toto" non toto $ test "$maVariable" = "toto" && echo "oui toto" || echo "non toto" non toto $ set |grep maVariable $
Et ces précautions de mettre des éléments en plus de chaque côté de l'égalité (l'underscore, les guillemets) s'appliquent aussi dans le cas que tu cites d'une variable existante mais vide (qui est un cas assez ressemblant au premier pour qu'on s'autorise à ne pas faire de distinction lors des tests)
Tu n'as pas compris ma phrase. Je disais "ça rassure de mettre set -u car on sait que ainsi, on l'on ne pourra pas utiliser (afficher, tester) des variables inexistantes (c'est une barrière facultative que l'on s'impose volontairement)".
Mais bien évidemment, si tu utilises des variables qui seront remplies (créées) uniquement dans certains cas particuliers (style "si la variable est remplie je fais telle action en plus") tu ne peux plus mettre set -u car au premier test de ta variable, si celle-ci n'existe pas le script plantera. Mais t'es pas obligé de mettre set -u si tu ne le veux pas. Cette phrase était destinée à jack-ft pour expliquer pourquoi certains admins imposent un set -u dans le .profile => pour se protéger contre les erreurs style "j'utilise mavariable alors qu'elle se nomme en réalité maVariable" (mais dans ce cas j'y rajouterais aussi set -e pour planter le script si erreur).
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]
je voudrais que nous puissions formaliser(?) tout ça. sereinement;
les états d'une variable
avant son utilisation, il existe plusieurs états possibles pour une variable :
- "non état" : elle n'existe pas (pas déclarée, ou supprimée unset v)
- déclarée (declare v)
- assignée
- sans valeur (v='')
- avec une valeur (v='V')
plusieurs tests sont possibles :
1.et 2.3a.
Code : Sélectionner tout - Visualiser dans une fenêtre à part declare -p v &>/dev/null3b.
Code : Sélectionner tout - Visualiser dans une fenêtre à part test -v v
Code : Sélectionner tout - Visualiser dans une fenêtre à part test -n "$v"
Tout à fait d'accord avec les états d'âme d'une variable...
mais peut-on distinguer les deux premiers cas (unset et déclarée), c'est-à-dire avoir l'information qu'une variable est déclarée ?
Comme je ne connaissais pas test -v, j'avais produit il y a quelque temps le tableau suivant (auquel je me réfère en cas de doute (et de flemme)):
Code x : 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 +=======================+=========+=========+=========+ | Instruction | unset V | V='' | V='X' | +-----------------------+---------+---------+---------+ | State of V | unset | empty | set | +=======================+=========+=========+=========+ | "${V-D}" | 'D' | '' | 'X' | +-----------------------+---------+---------+---------+ | "${V:-D}" | 'D' | 'D' | 'X' | +-----------------------+---------+---------+---------+ | "${V+D}" | '' | 'D' | 'D' | +-----------------------+---------+---------+---------+ | "${V:+D}" | '' | '' | 'D' | +=======================+=========+=========+=========+ | test -z "${V+D}" | true | F | F | unset +-----------------------+---------+---------+---------+ | test -z "${V-D}" | F | true | F | empty (set to empty) +-----------------------+---------+---------+---------+ | test -n "${V:+D}" | F | F | true | set (but not empty) +=======================+=========+=========+=========+ | test -n "${V+D}" | F | true | true | not unset (set or empty) +-----------------------+---------+---------+---------+ | test -n "${V-D}" | true | F | true | not empty (unset or set) +-----------------------+---------+---------+---------+ | test -z "${V:+D}" | true | true | F | not set (unset or empty) +=======================+=========+=========+=========+ | "${V-A}${V-B}" = "AB" | true | F | F | unset +=======================+=========+=========+=========+
Et ça marche même avec le set -u:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 % cat test.sh #!/bin/bash if test "$a" = ""; then echo "a vide (ou non initialisée)"; else echo "a pas vide"; fi set -u if test -z "${a+D}"; then echo "Attention: 'a' n'est pas initialisée"; fi if test "$a" = ""; then echo "a vide (ou non initialisée)"; else echo "a pas vide"; fi
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 % ./test.sh a vide (ou non initialisée) Attention: 'a' n'est pas initialisée ./test.sh: line 9: a: unbound variable
c'est ce que je montre avec &>/dev/null declare -p, cette commande à qui on fournit une variable déclarée retourne 0 (vrai).peut-on distinguer les deux premiers cas (unset et déclarée), c'est-à-dire avoir l'information qu'une variable est déclarée ?
hmmm
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 $ unset foo $ test -v foo $ echo $? 1 $ foo='' $ test -v foo $ echo $? 0 $ foo='bar' $ test -v foo $ echo $? 0
test -v teste si une variable est assignée, pas si cette assignation a une valeur.
c'est ce que j'ai dit : une valeur null ne vaut pas pas une valeur text/int
tout n'est limpide pour moi (je suis un utilisateur) ; pour faire vraiment bien il faudrait savoir entrer dans les entrailles du shell.
il paraît que c'est tout con : ce serait une boucle qui attend des instructions...
![]()
Pour moi, c'est plus 2 et 3 dans cette formulation pour test -v <-- ici on interroge l'ensemble pas le sujet lui-même
et le 3b devrait passer en 4 pour test -n <-- ici on interroge le sujet lui même
Ben oui.
[partiellement HS]
La plupart du temps, j'ai travaillé avec des langages à pointeurs (lisp, LOGO, smalltalk, Objective-C, java, etc.).
Dans certains de ces langages, une variable est une entité de première classe, elle peut être manipulée comme un élément du langage.
Ainsi, en lisp, on peut demander à une variable son nom, sa valeur, sa plist, etc.
On peut mettre une variable (un symbole, et non la "valeur" de la variable) en contenu d'une autre variable.
Souvent le langage offre des raccourcis pour accéder à la valeur d'une variable. Ainsi, pour accéder à la valeur contenue dans la variable dont le nom est "x", en lisp, on écrit beaucoup plus souvent x que (symbol-value 'x) (ou que (symbol-value (intern "x")) !)
De même pour l'affectation, on écrira plus (setq x (quelque chose)) que (set 'x (quelque chose)). Entre autres, parce que ça aide considérablement les compilateurs dans un contexte lexical pour produire du code efficace.
Du coup, il faut que le langage ait des formes spéciales (comme les macros, par exemple), de manière à ce que certains morceaux ne soient pas évalués. Dans (setq x (quelque chose)), la forme spéciale "setq" prend son premier argument tel quel, non évalué, l'objet "la variable x", vérifie que c'est bien un symbole, puis évalue le deuxième argument (quelque chose), qui doit retourner quelque chose, et enfin met cette valeur retournée dans le slot "symbol-value" de la variable x.
En LOGO, on n'a pas de SETQ. Du coup, on doit bien distinguer les variables de leur contenu, par exemple (SET "X :Y) met dans la variable dont le nom est "X" le contenu de la variable dont le nom est "Y".
En bash et dans d'autres langages, on distingue les l-value (grosso modo à gauche du signe "=") des r-values (grosso modo à droite du signe "=").
J'imagine que le test test -v v considère l'argument suivant le "-v" comme le nom d'une variable et va chercher, quelque part dans l'environnement du shell, s'il y a une assignation/correspondance entre ce nom de variable et une valeur (même une chaine vide).
Alors que le test test -n "$v" commence probablement par construire une chaine (délimitée par les guillemets) dans laquelle il fait l'expansion des variables. J'imagine que, voyant la "chaine" de 2 caractères $v, il se rend compte qu'il doit trouver la valeur de la variable dont le nom est "v" et, pour ce faire, il va chercher quelque part dans l'environnement du shell, s'il y a une assignation/correspondance entre ce nom de variable et une valeur, puis, s'il n'y en a pas et que l'option "nounset" est positionnée par set -u, il déclenche une erreur ou bien sinon il remplace la "chaine" de 2 caractères $v par la valeur contenue dans la variable dont le nom est "v" (ou par une chaine vide s'il ne trouve pas de correspondance) et ensuite il fait le test correspondant à l'option "-n", c'est-à-dire vérifier si cette chaine est vide... Ouf !
Félicitations à ceux qui ont réussi à perdre leur temps à tout lire !
[/partiellement HS]
Partager