Como testar se um parâmetro foi configurado para a string vazia?

1

Eu quero testar se um parâmetro é uma string vazia "" .

Quando o parâmetro não está definido, o teste deve falhar.

  1. Por que o seguinte não é bem-sucedido?

    $ unset aa
    $ if [ ${aa}=="" ]; then echo yes; else echo no; fi
    yes
    
  2. O que devo fazer em vez disso?

por Tim 27.01.2018 / 21:04

3 respostas

4

test , ou seja, [ , precisa de espaços em branco em torno dos operadores, basicamente porque senão foo== seria considerado como contendo um operador, mesmo que seja uma cadeia válida. A construção [[ .. ]] funciona da mesma forma. (Veja esta questão e BashFAQ 031 para a diferença [ vs [[ .

Portanto, [ ${aa}=="" ] será sempre verdadeiro, pois [ string ] é igual a [ -n string ] , ou seja, testa se a string não está vazia. E aqui a string contém pelo menos == .

Em seguida, [ ${aa} == "" ] será um erro se aa não estiver definido ou vazio, pois uma variável vazia expandida sem aspas desaparece e [ == foo ] não é um teste válido. Se aa tiver um valor não vazio, é falso. ( [[ ${aa} == "" ]] funcionaria mesmo sem as aspas, pois [[ .. ]] é especial.)

É claro que [ "${aa}" == "" ] testaria que aa não está definido ou está vazio, o mesmo que [ -z "${aa}" ] .

Para testar se está definido e vazio, poderíamos usar [ "${aa+x}" ] && [ -z "$aa" ] , ou uma combinação bacana deles, roubada de um resposta de @ Stéphane Chazelas :

if [ "${aa+x$aa}" = "x" ] ; then
    echo "aa is empty but set"
fi

(isso funciona, pois se aa não estiver definido, a expansão + expandirá para a sequência vazia e, se estiver definida, será expandida para x$aa , que é apenas x se aa estiver vazio. )

$ foo() { [ "${1+x$1}" = "x" ] && echo "set but empty" || echo "unset or non-empty"; }    
$ foo; foo ""; foo bar
unset or non-empty
set but empty
unset or non-empty
    
por 27.01.2018 / 23:17
6

O teste (tentado) $aa == "" é equivalente a comparar duas strings vazias entre si, o que resulta em um resultado verdadeiro. Isso ocorre porque o shell expandirá as variáveis não definidas para a string vazia. Sem os espaços em torno de == , o teste será sempre verdadeiro, pois é o mesmo que testar na cadeia de dois caracteres == . Essa string é sempre verdadeira.

Em vez disso, em bash :

$ unset aa
$ if [ -v aa ]; then echo Set; else echo Not set; fi
Not set
$ aa=""
$ if [ -v aa ]; then echo Set; else echo Not set; fi
Set

O teste completo para uma string vazia seria, portanto,

if [ -v aa ] && [ -z "$aa" ]; then
    echo Set but empty
fi

De help test em bash :

-v VAR True if the shell variable VAR is set.

Ou, na seção "EXPRESSÕES CONDICIONAIS" do manual bash :

-v varname

True if the shell variable varname is set (has been assigned a value).

Com o teste -v , você testa o nome da variável, em vez de seu valor.

Se você realmente quiser fazer uma comparação de strings, você poderia fazer algo como

if [[ "${aa-InvalidValue}" != "InvalidValue" ]] && [ -z "$aa" ]; then
    echo Set but empty
fi

A expansão ${variable-value} expandirá para value se variable não estiver definido.

Observe que o ${variable:-value} muito semelhante expandirá para value se variable não estiver definido como ou nulo (a string vazia).

    
por 27.01.2018 / 21:11
3

Primeiro, e suponho que você saiba, o == requer espaços ao redor dele. O uso de == é válido somente em bash, ksh e zsh, use melhor = . Além disso, as variáveis expandidas dentro de um teste devem ser citadas. Então, vou supor que a linha é realmente:

unset aa ; if [ "${aa}" = "" ]; then echo yes; else echo no; fi

Com isso, suas perguntas:

Por que o seguinte não é bem-sucedido?

Porque a expansão de uma planície unset var é idêntica à expansão de uma variável simples definida como nula (de qual teste '[' poderia fazer).

I mean, "$aa" is the same value for both an unset aa or a null aa.

Para mostrar como isso funciona, tente este script (note que o script é sh, funciona da mesma forma em dash, bash, ksh e / ou zsh):

#!/bin/sh

blanktest(){
    if [ "${aa}" = "" ]; then echo "$1 yes"; else echo "$1 no"; fi
}

unset aa; blanktest unset
unset aa; aa="";  blanktest blank
unset aa; aa="e"; blanktest value

Que, na execução, produzirá:

$ ./script
unset yes
blank yes
value no

O que devo fazer em vez disso?

Use uma expansão de parâmetro chamada "Use Alternative Value". :

${aa+x}

que produzirá um x se a variável for definida (nula ou valor) e um nulo se a variável não for definida.

Use este teste:

[ "x${aa}x" = "x${aa+x}" ] && echo yes || echo no

Script de teste (novamente, compatível com sh):

#!/bin/sh

blanktest(){
    if [ "x${aa}x" = "x${aa+x}" ]; then echo "$1 yes"; else echo "$1 no"; fi
}

unset aa; blanktest unset
unset aa; aa="";  blanktest blank
unset aa; aa="e"; blanktest value

Na execução, será impresso:

$ ./script
unset no
blank yes
value no

Existem várias variações possíveis, se você estiver interessado.

    
por 27.01.2018 / 23:33

Tags