veuillez prendre l'habitude d'utiliser [-z "$ mystr"] par opposition à [-z $ mystr]
Charles Duffy
comment faire la chose inverse? Je veux dire quand la chaîne n'est pas nulle
Ouvrez le chemin
1
@flow: What about[ -n "${VAR+x}"] && echo not null
Lekensteyn
1
@CharlesDuffy J'ai déjà lu ceci dans de nombreuses ressources en ligne. Pourquoi est-ce préféré?
ffledgling
6
@Ayos car si vous n'avez pas de guillemets, le contenu de la variable est fractionné et globalisé; si c'est une chaîne vide, elle devient [ -z ]au lieu de [ -z "" ]; s'il a des espaces, il devient [ -z "my" "test" ]au lieu de [ -z my test ]; et si c'est le cas [ -z * ], le *est remplacé par les noms des fichiers de votre répertoire.
Charles Duffy
Réponses:
138
Je pense que la réponse que vous recherchez est implicite (sinon énoncée) par la réponse de Vinko , bien qu'elle ne soit pas énoncée simplement. Pour distinguer si VAR est défini mais vide ou non défini, vous pouvez utiliser:
if[-z "${VAR+xxx}"];then echo VAR is not set at all;fiif[-z "$VAR"]&&["${VAR+xxx}"="xxx"];then echo VAR is set but empty;fi
Vous pouvez probablement combiner les deux tests de la deuxième ligne en un seul avec:
if[-z "$VAR"-a "${VAR+xxx}"="xxx"];then echo VAR is set but empty;fi
Cependant, si vous lisez la documentation d'Autoconf, vous constaterez qu'ils ne recommandent pas de combiner les termes avec « -a» et recommandent d'utiliser des tests simples séparés combinés avec &&. Je n'ai pas rencontré de système présentant un problème; cela ne veut pas dire qu'ils n'existaient pas (mais ils sont probablement extrêmement rares de nos jours, même s'ils n'étaient pas aussi rares dans un passé lointain).
J'ai récemment été interrogé par e-mail sur cette réponse avec la question:
Vous utilisez deux tests, et je comprends bien le second, mais pas le premier. Plus précisément, je ne comprends pas la nécessité d'une expansion variable
if[-z "${VAR+xxx}"];then echo VAR is not set at all;fi
Cela ne ferait-il pas la même chose?
if[-z "${VAR}"];then echo VAR is not set at all;fi
Bonne question - la réponse est «Non, votre alternative plus simple ne fait pas la même chose».
Supposons que j'écris ceci avant votre test:
VAR=
Votre test dira "VAR n'est pas du tout défini", mais le mien dira (par implication car il ne fait écho à rien) "VAR est défini mais sa valeur peut être vide". Essayez ce script:
(
unset VARif[-z "${VAR+xxx}"];then echo JL:1 VAR is not set at all;fiif[-z "${VAR}"];then echo MP:1 VAR is not set at all;fi
VAR=if[-z "${VAR+xxx}"];then echo JL:2 VAR is not set at all;fiif[-z "${VAR}"];then echo MP:2 VAR is not set at all;fi)
La sortie est:
JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all
Dans la deuxième paire de tests, la variable est définie, mais elle est définie sur la valeur vide. C'est la distinction que font les notations ${VAR=value}et ${VAR:=value}. Idem pour ${VAR-value}et ${VAR:-value}, et ${VAR+value}et ${VAR:+value}, et ainsi de suite.
Comme Gili le souligne dans sa réponse , si vous utilisez bashl' set -o nounsetoption, la réponse de base ci-dessus échoue unbound variable. On y remédie facilement:
if[-z "${VAR+xxx}"];then echo VAR is not set at all;fiif[-z "${VAR-}"]&&["${VAR+xxx}"="xxx"];then echo VAR is set but empty;fi
Ou vous pouvez annuler l' set -o nounsetoption avec set +u( set -uéquivalent à set -o nounset).
Le seul problème que j'ai avec cette réponse est qu'elle accomplit sa tâche d'une manière plutôt indirecte et peu claire.
Suisse
3
Pour ceux qui souhaitent rechercher la description de ce que cela signifie dans la page de manuel bash, recherchez la section "Expansion des paramètres" puis ce texte: "Lorsque vous n'effectuez pas de développement de sous-chaînes, en utilisant les formulaires documentés ci-dessous, bash teste pour paramètre non défini ou nul [«null» signifiant la chaîne vide]. L'omission des deux-points entraîne un test uniquement pour un paramètre non défini (...) $ {paramètre: + mot}: utilisez une autre valeur. Si paramètre est nul ou non défini, rien n'est substitué, sinon le développement du mot est remplacé. "
David Tonhofer
2
@Swiss Ce n'est ni flou ni indirect, mais idiomatique. Peut-être pour un programmeur peu familier avec ${+}et ${-}ce n'est pas clair, mais la familiarité avec ces constructions est essentielle si l'on veut être un utilisateur compétent du shell.
J'ai fait beaucoup de tests à ce sujet; car les résultats dans mes scripts étaient incohérents. Je suggère aux gens de se pencher sur l' [ -v VAR ]approche " " avec bash -s v4.2 et au - delà .
-z fonctionne également pour les variables non définies. Pour faire la distinction entre un indéfini et un défini, vous utiliseriez les éléments listés ici ou, avec des explications plus claires, ici .
La manière la plus propre est d'utiliser l'expansion comme dans ces exemples. Pour obtenir toutes vos options, consultez la section Extension des paramètres du manuel.
Autre mot:
~$ unset FOO
~$ if test ${FOO+defined};then echo "DEFINED";fi~$ FOO=""~$ if test ${FOO+defined};then echo "DEFINED";fi
DEFINED
Valeur par défaut:
~$ FOO=""~$ if test "${FOO-default value}";then echo "UNDEFINED";fi~$ unset FOO
~$ if test "${FOO-default value}";then echo "UNDEFINED";fi
UNDEFINED
Bien sûr, vous utiliseriez l'un de ceux-ci différemment, en mettant la valeur souhaitée au lieu de «valeur par défaut» et en utilisant l'expansion directement, le cas échéant.
Mais je veux distinguer si la chaîne est "" ou n'a jamais été définie. Est-ce possible?
Setjmp
1
cette réponse ne dit comment faire la distinction entre ces deux cas; suivez le lien faq bash qu'il fournit pour plus de discussion.
Charles Duffy
1
J'ai ajouté qu'après son commentaire, Charles
Vinko Vrsalovic
2
Recherchez «Expansion des paramètres» dans la page de manuel de bash pour toutes ces «astuces». Exemple: $ {foo: -default} pour utiliser une valeur par défaut, $ {foo: = default} pour attribuer la valeur par défaut, $ {foo:? Error message} pour afficher un message d'erreur si foo n'est pas défini, etc.
Jouni K . Seppänen
18
Guide de création de scripts bash avancé, 10.2. Substitution de paramètres:
$ {var + blahblah}: si var est défini, 'blahblah' est remplacé par l'expression, sinon nul est remplacé
$ {var-blahblah}: si var est défini, il est lui-même substitué, sinon 'blahblah' est remplacé
$ {var? blahblah}: si var est défini, il est remplacé, sinon la fonction existe avec 'blahblah' comme message d'erreur.
pour baser la logique de votre programme sur la définition ou non de la variable $ mystr, vous pouvez faire ce qui suit:
isdefined=0
${mystr+ export isdefined=1}
maintenant, si isdefined = 0 alors la variable n'était pas définie, si isdefined = 1 la variable a été définie
Cette façon de vérifier les variables est meilleure que la réponse ci-dessus car elle est plus élégante, plus lisible, et si votre shell bash a été configuré en erreur lors de l'utilisation de variables non définies (set -u), le script se terminera prématurément.
Autres trucs utiles:
pour avoir une valeur par défaut de 7 assignée à $ mystr si elle n'était pas définie, et la laisser intacte sinon:
mystr=${mystr-7}
pour imprimer un message d'erreur et quitter la fonction si la variable n'est pas définie:
: ${mystr? not defined}
Attention ici que j'ai utilisé ':' pour ne pas faire exécuter le contenu de $ mystr en tant que commande au cas où il serait défini.
Je ne savais pas pour le? syntaxe pour les variables BASH. C'est une belle prise.
suisse
Cela fonctionne également avec des références de variables indirectes. Ce passe: var= ; varname=var ; : ${!varname?not defined}ce qui se termine: varname=var ; : ${!varname?not defined}. Mais c'est une bonne habitude à utiliser set -uqui fait de même beaucoup plus facilement.
ceving le
11
Un résumé des tests.
[-n "$var"]&& echo "var is set and not empty"[-z "$var"]&& echo "var is unset or empty"["${var+x}"="x"]&& echo "var is set"# may or may not be empty[-n "${var+x}"]&& echo "var is set"# may or may not be empty[-z "${var+x}"]&& echo "var is unset"[-z "${var-x}"]&& echo "var is set and empty"
Bonne pratique en bash. Parfois, les chemins de fichiers ont des espaces, ou pour se protéger contre l'injection de commande
k107
1
Je pense que ${var+x}ce n'est pas nécessaire, sauf si les noms de variables sont autorisés à contenir des espaces.
Anne van Rossum
Pas seulement de bonnes pratiques; il est nécessaire avec [pour obtenir des résultats corrects. Si varest non défini ou vide, [ -n $var ]réduit à [ -n ]qui a l'état de sortie 0, tandis que [ -n "$var" ]a l'état de sortie attendu (et correct) de 1.
chepner
5
https://stackoverflow.com/a/9824943/14731 contient une meilleure réponse (une qui est plus lisible et fonctionne avec set -o nounsetactivé). Cela fonctionne à peu près comme ceci:
if[-n "${VAR-}"];then
echo "VAR is set and is not empty"elif["${VAR+DEFINED_BUT_EMPTY}"="DEFINED_BUT_EMPTY"];then
echo "VAR is set, but empty"else
echo "VAR is not set"fi
Je ne trouve pas cela dans aucune des pages de manuel (pour bash ou test) mais cela fonctionne pour moi .. Une idée des versions ajoutées?
Ash Berlin-Taylor
1
Il est documenté dans les expressions conditionnelles , référencées à partir de l' testopérateur à la fin de la section Bourne Shell Builtins . Je ne sais pas quand il a été ajouté, mais ce n'est pas dans la version Apple de bash(basée sur bash3.2.51), donc c'est probablement une fonctionnalité 4.x.
Jonathan Leffler
1
Cela ne fonctionne pas pour moi avec GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu). L'erreur est -bash: [: -v: unary operator expected. Par un commentaire ici , il faut au minimum bash 4.2 pour fonctionner.
Acumenus
Merci d'avoir vérifié quand il est devenu disponible. Je l'avais déjà utilisé sur divers systèmes, mais soudainement cela n'a pas fonctionné. Je suis venu ici par curiosité et oui, bien sûr, la bash sur ce système est une bash 3.x.
pour ne pas jeter ce vélo encore plus loin, mais je voulais ajouter
shopt -s -o nounset
est quelque chose que vous pouvez ajouter en haut d'un script, ce qui entraînera une erreur si les variables ne sont déclarées nulle part dans le script. Le message que vous voyez est unbound variable, mais comme d'autres le mentionnent, il n'attrapera pas une chaîne vide ou une valeur nulle. Pour nous assurer qu'aucune valeur individuelle n'est vide, nous pouvons tester une variable au fur et à mesure qu'elle est développée avec ${mystr:?}, également appelée expansion du signe dollar, ce qui entraînerait une erreur avec parameter null or not set.
Cela peut être appliqué en sélectionnant visuellement les lignes pertinentes, puis en les tapant :. La barre de commandes pré-remplit avec :'<,'>. Collez la commande ci-dessus et appuyez sur Entrée.
Testé sur cette version de Vim:
VIM -ViIMproved7.3(2010Aug15, compiled Aug22201515:38:58)Compiled by root@apple.com
Les utilisateurs Windows peuvent souhaiter des fins de ligne différentes.
Ecrire une fonction n'est pas une mauvaise idée; invoquer grepest horrible. Notez que bashprend ${!var_name}en charge comme moyen d'obtenir la valeur d'une variable dont le nom est spécifié dans $var_name, donc name=value; value=1; echo ${name} ${!name}renvoie value 1.
Jonathan Leffler
0
Une version plus courte pour tester une variable non définie peut simplement être:
call set sans aucun argument .. il affiche tous les vars définis ..
les derniers sur la liste seraient ceux définis dans votre script ..
ainsi vous pourriez diriger sa sortie vers quelque chose qui pourrait comprendre ce qui est défini et ce qui ne l'est pas
Je n'ai pas voté contre cela, mais c'est un peu un marteau pour casser une petite noix.
Jonathan Leffler
En fait, j'aime mieux cette réponse que la réponse acceptée. Ce qui est fait dans cette réponse est clair. La réponse acceptée est bancale comme l'enfer.
suisse
Il semble que cette réponse soit plus un effet secondaire de l'implémentation de "set" que quelque chose de souhaitable.
[ -n "${VAR+x}"] && echo not null
[ -z ]
au lieu de[ -z "" ]
; s'il a des espaces, il devient[ -z "my" "test" ]
au lieu de[ -z my test ]
; et si c'est le cas[ -z * ]
, le*
est remplacé par les noms des fichiers de votre répertoire.Réponses:
Je pense que la réponse que vous recherchez est implicite (sinon énoncée) par la réponse de Vinko , bien qu'elle ne soit pas énoncée simplement. Pour distinguer si VAR est défini mais vide ou non défini, vous pouvez utiliser:
Vous pouvez probablement combiner les deux tests de la deuxième ligne en un seul avec:
Cependant, si vous lisez la documentation d'Autoconf, vous constaterez qu'ils ne recommandent pas de combiner les termes avec «
-a
» et recommandent d'utiliser des tests simples séparés combinés avec&&
. Je n'ai pas rencontré de système présentant un problème; cela ne veut pas dire qu'ils n'existaient pas (mais ils sont probablement extrêmement rares de nos jours, même s'ils n'étaient pas aussi rares dans un passé lointain).Vous pouvez trouver les détails de ceux-ci, ainsi que d'autres extensions de paramètres de shell connexes , la commande
test
ou[
et les expressions conditionnelles dans le manuel Bash.J'ai récemment été interrogé par e-mail sur cette réponse avec la question:
Bonne question - la réponse est «Non, votre alternative plus simple ne fait pas la même chose».
Supposons que j'écris ceci avant votre test:
Votre test dira "VAR n'est pas du tout défini", mais le mien dira (par implication car il ne fait écho à rien) "VAR est défini mais sa valeur peut être vide". Essayez ce script:
La sortie est:
Dans la deuxième paire de tests, la variable est définie, mais elle est définie sur la valeur vide. C'est la distinction que font les notations
${VAR=value}
et${VAR:=value}
. Idem pour${VAR-value}
et${VAR:-value}
, et${VAR+value}
et${VAR:+value}
, et ainsi de suite.Comme Gili le souligne dans sa réponse , si vous utilisez
bash
l'set -o nounset
option, la réponse de base ci-dessus échoueunbound variable
. On y remédie facilement:Ou vous pouvez annuler l'
set -o nounset
option avecset +u
(set -u
équivalent àset -o nounset
).la source
${+}
et${-}
ce n'est pas clair, mais la familiarité avec ces constructions est essentielle si l'on veut être un utilisateur compétent du shell.set -o nounset
enabled.[ -v VAR ]
approche " " avec bash -s v4.2 et au - delà .-z fonctionne également pour les variables non définies. Pour faire la distinction entre un indéfini et un défini, vous utiliseriez les éléments listés ici ou, avec des explications plus claires, ici .
La manière la plus propre est d'utiliser l'expansion comme dans ces exemples. Pour obtenir toutes vos options, consultez la section Extension des paramètres du manuel.
Autre mot:
Valeur par défaut:
Bien sûr, vous utiliseriez l'un de ceux-ci différemment, en mettant la valeur souhaitée au lieu de «valeur par défaut» et en utilisant l'expansion directement, le cas échéant.
la source
Guide de création de scripts bash avancé, 10.2. Substitution de paramètres:
pour baser la logique de votre programme sur la définition ou non de la variable $ mystr, vous pouvez faire ce qui suit:
maintenant, si isdefined = 0 alors la variable n'était pas définie, si isdefined = 1 la variable a été définie
Cette façon de vérifier les variables est meilleure que la réponse ci-dessus car elle est plus élégante, plus lisible, et si votre shell bash a été configuré en erreur lors de l'utilisation de variables non définies
(set -u)
, le script se terminera prématurément.Autres trucs utiles:
pour avoir une valeur par défaut de 7 assignée à $ mystr si elle n'était pas définie, et la laisser intacte sinon:
pour imprimer un message d'erreur et quitter la fonction si la variable n'est pas définie:
Attention ici que j'ai utilisé ':' pour ne pas faire exécuter le contenu de $ mystr en tant que commande au cas où il serait défini.
la source
var= ; varname=var ; : ${!varname?not defined}
ce qui se termine:varname=var ; : ${!varname?not defined}
. Mais c'est une bonne habitude à utiliserset -u
qui fait de même beaucoup plus facilement.Un résumé des tests.
la source
${var+x}
ce n'est pas nécessaire, sauf si les noms de variables sont autorisés à contenir des espaces.[
pour obtenir des résultats corrects. Sivar
est non défini ou vide,[ -n $var ]
réduit à[ -n ]
qui a l'état de sortie 0, tandis que[ -n "$var" ]
a l'état de sortie attendu (et correct) de 1.https://stackoverflow.com/a/9824943/14731 contient une meilleure réponse (une qui est plus lisible et fonctionne avec
set -o nounset
activé). Cela fonctionne à peu près comme ceci:la source
La manière explicite de vérifier une variable en cours de définition serait:
la source
test
opérateur à la fin de la section Bourne Shell Builtins . Je ne sais pas quand il a été ajouté, mais ce n'est pas dans la version Apple debash
(basée surbash
3.2.51), donc c'est probablement une fonctionnalité 4.x.GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
. L'erreur est-bash: [: -v: unary operator expected
. Par un commentaire ici , il faut au minimum bash 4.2 pour fonctionner.une autre option: l'extension "list array index" :
le seul moment où cela se développe en chaîne vide est quand
foo
n'est pas défini, vous pouvez donc le vérifier avec la chaîne conditionnelle:devrait être disponible dans n'importe quelle version de bash> = 3.0
la source
pour ne pas jeter ce vélo encore plus loin, mais je voulais ajouter
est quelque chose que vous pouvez ajouter en haut d'un script, ce qui entraînera une erreur si les variables ne sont déclarées nulle part dans le script. Le message que vous voyez est
unbound variable
, mais comme d'autres le mentionnent, il n'attrapera pas une chaîne vide ou une valeur nulle. Pour nous assurer qu'aucune valeur individuelle n'est vide, nous pouvons tester une variable au fur et à mesure qu'elle est développée avec${mystr:?}
, également appelée expansion du signe dollar, ce qui entraînerait une erreur avecparameter null or not set
.la source
Le manuel de référence de Bash est une source d'informations faisant autorité sur bash.
Voici un exemple de test d'une variable pour voir si elle existe:
(De la section 6.3.2 .)
Notez que l'espace après l'ouverture
[
et avant le]
n'est pas facultatif .Conseils pour les utilisateurs de Vim
J'avais un script qui avait plusieurs déclarations comme suit:
Mais je voulais qu'ils s'en remettent à toutes les valeurs existantes. Alors je les ai réécrits pour ressembler à ceci:
J'ai pu automatiser cela dans vim en utilisant une expression régulière rapide:
Cela peut être appliqué en sélectionnant visuellement les lignes pertinentes, puis en les tapant
:
. La barre de commandes pré-remplit avec:'<,'>
. Collez la commande ci-dessus et appuyez sur Entrée.Testé sur cette version de Vim:
Les utilisateurs Windows peuvent souhaiter des fins de ligne différentes.
la source
Voici ce que je pense être un moyen beaucoup plus clair de vérifier si une variable est définie:
Utilisez-le comme suit:
la source
grep
est horrible. Notez quebash
prend${!var_name}
en charge comme moyen d'obtenir la valeur d'une variable dont le nom est spécifié dans$var_name
, doncname=value; value=1; echo ${name} ${!name}
renvoievalue 1
.Une version plus courte pour tester une variable non définie peut simplement être:
la source
call set sans aucun argument .. il affiche tous les vars définis ..
les derniers sur la liste seraient ceux définis dans votre script ..
ainsi vous pourriez diriger sa sortie vers quelque chose qui pourrait comprendre ce qui est défini et ce qui ne l'est pas
la source