Por que essa verificação condicional do bash funciona com [[-n ..]] mas não [-n ..]? [duplicado]

9

Eu tenho um script que não consegue detectar seqüências de comprimento zero, o script usa [ -n $value ] em uma expressão condicional bash, ou seja,

#!/usr/bin/env bash

value=""
if [ -n $value ]
then
    echo "value is non-zero"
fi

resultado

value is non-zero

Se eu usar [[ -n $value ]] , isso funciona, por exemplo

#!/usr/bin/env bash

value=""
if [[ -n $value ]]
then
    echo "value is non-zero"
fi

usando [[ não produz saída como esperado. Na página do manual:

   [[ 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.

Eu não posso dar uma explicação para o comportamento disso.
Por que [[ detecta sequências de comprimento zero, mas [ não?

    
por the_velour_fog 30.11.2015 / 05:24

2 respostas

17

isso ocorre porque [[ recebe uma expressão , e [ aceita argumentos que são traduzidos em uma expressão .

[[ é sintaxe - não é um comando interno como [ is, mas sim [[ é um comando composto e é mais parecido com { ou ( do que é para [ .

em qualquer caso, porque [[ é analisado ao lado $expansions , não há dificuldade em entender a diferença entre uma expansão com valor nulo e um operando ausente.

[ , no entanto, é uma execução de rotina após todas as expansões de linha de comando já ocorreram e, quando avalia suas expressões, $null_expansion já foi expandido para nada e tudo o que recebe é [ -n ] , o que não pode ser uma expressão válida. [ é spec'd para retornar true para um caso não-nulo de argumento único - como acontece para -n here - mas o mesma especificação continua dizendo ...

The two commands:

  test "$1"
  test ! "$1"

could not be used reliably on some historical systems. Unexpected results would occur if such a string expression were used and $1 expanded to !, (, or a known unary primary (such as -n). Better constructs are:

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

existem vantagens e desvantagens para ambos os formulários. As expressões [ podem ser construídas em fora de , e assim:

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

... pode ser uma maneira perfeitamente válida de criar um teste, mas não é possível com:

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

... o que é um comando sem sentido. As diferenças são inteiramente devidas ao ponto de análise da linha de comando no qual o teste é executado.

    
por 30.11.2015 / 05:44
9

As variáveis não precisam ser citadas duas vezes em [[ ]] , mas devem ser citadas como [ ] .

Sem as aspas, se $value for uma string vazia, [ -n $value ] será exatamente igual a [ "-n" ] . "-n" é um teste de sequência e avalia como não-vazio e, portanto, verdadeiro, portanto, o teste é bem-sucedido.

(por que? porque -n STRING e STRING são os mesmos para [ aka test - ambos são um teste para string-is-not-empty)

Outras experiências indicam que este parece ser o caso de todos os testes de operando único, incluindo operadores de arquivo - se não houver nenhum operando, [ ] trata o único argumento como um teste de sequência. Isso provavelmente seria considerado um bug e corrigido se não fosse um fato histórico que os roteiristas passaram a depender ao longo das décadas - e a mudança iria quebrar um número incontável de scripts existentes.

Com aspas, [ -n "$value" ] é exatamente igual a [ -n "" ] , então o teste falha.

[[ ... ]] é muito mais indulgente sobre a cotação de variáveis - a cotação é opcional e funciona da mesma forma com ou sem cotações.

    
por 30.11.2015 / 05:36

Tags