Pourquoi cette vérification conditionnelle bash fonctionne-t-elle avec ] mais pas ?

J'ai un script qui ne détecte pas les strings de longueur zéro, le script utilise [ -n $value ] dans une expression conditionnelle bash, ie

 #!/usr/bin/env bash value="" if [ -n $value ] then echo "value is non-zero" fi 

résultat

la valeur est non nulle

Si j'utilise [[ -n $value ]] ça marche, c'est à dire

 #!/usr/bin/env bash value="" if [[ -n $value ]] then echo "value is non-zero" fi 

using [[ ne produit pas de sortie comme prévu. De la page de manuel:

  [[ expression ]] Return a status of 0 or 1 depending on the evaluation of the conditional expression expression. Expressions are composed of the pri‐ maries described below under CONDITIONAL EXPRESSIONS. Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed. Conditional operators such as -f must be unquoted to be recognized as primaries. 

Je ne peux pas faire une explication pour le comportement de cela.
Pourquoi [[ détecte-t-on les strings de longueur nulle mais [ doesnt?

c'est parce que [[ prend une expression , et [ prend des arguments qu'elle traduit en une expression .

[[ est une syntaxe – ce n'est pas une command embeddede comme [ est, mais plutôt [[ est une command composée et est plus proche de { ou ( que de [ .

dans tous les cas, parce que [[ est analysé à côté de $expansions , il n'a aucune difficulté à comprendre la différence entre une extension à valeur nulle et un opérande manquant.

[ , cependant, est une exécution de routine après que toutes les expansions de command line ont déjà eu lieu, et au moment où il évalue ses expressions, $null_expansion a déjà été étendu dans rien et ainsi tout ce qu'il reçoit est [ -n ] , qui peut ne pas être une expression valide. [ est spec'd pour renvoyer vrai pour un cas d'argument simple non-nul – comme il le fait pour -n ici – mais la même spécification continue à dire …

Les deux commands:

  test "$1" test ! "$1" 

ne pouvait pas être utilisé de manière fiable sur certains systèmes historiques. Des résultats inattendus se produiraient si une telle expression de string était utilisée et que $1 étendu à ! , ( ou un primaire unaire connu (tel que -n ) . ) Les meilleurs constructs sont:

  test -n "$1" test -z "$1" 

il y a des hauts et des bas aux deux forms. [ expressions peuvent être construites à partir d' extensions, et ainsi:

 [ "-${z:-n}" "$var" ] 

… pourrait être un moyen parfaitement valide de build un test, mais n'est pas faisable avec:

 [[ "-${z:-n}" "$var" ]] 

… qui est une command absurde. Les différences sont entièrement dues au point d'parsing de command line auquel le test est exécuté.

Les variables ne doivent pas être cotées dans [[ ]] mais elles doivent être citées pour [ ] .

Sans les guillemets, si $value est une string vide, [ -n $value ] est exactement la même que [ "-n" ] . "-n" est un test de string et évalue comme non-vide et donc vrai, de sorte que le test réussit.

(pourquoi? parce que -n STRING et STRING sont les mêmes pour [ aka test – ils sont à la fois un test pour ssortingng-is-not-empty)

D'autres expériences indiquent que cela semble être le cas pour tous les tests à opérande unique, y compris les opérateurs de files – s'il n'y a pas d'opérande, [ ] traite l'argument unique comme un test de string. Cela serait probablement considéré comme un bug et corrigé si ce n'était pas un fait historique que les scénaristes ont fini par dépendre au fil des décennies – et le changer briserait un nombre incalculable de scripts existants.

Avec des guillemets, [ -n "$value" ] est exactement la même que [ -n "" ] , le test échoue.

[[ ... ]] est beaucoup plus indulgent sur la citation des variables – la citation est facultative et fonctionne de la même façon avec ou sans guillemets.