Comparação de strings com integer em [[test

6

Eu estava olhando para a discussão entre Kusalananda e xhienne aqui , onde é mencionado que [ "" -ge 2 ] não é válido teste produzindo um erro em bash --posix e outros shells compatíveis com POSIX.

bash-4.3$ [ "" -gt 10 ]
bash: [: : integer expression expected
bash-4.3$ [ '' -gt 10 ]
bash: [: : integer expression expected

Tudo bem lá. Por curiosidade, tentei o mesmo com [[ .

bash-4.3$ [[ "" -gt 10 ]] && echo "YES"
bash-4.3$ [[ "" -gt 0 ]] && echo "YES"
bash-4.3$ [[ "" -gt -1 ]] && echo "YES"
YES
bash-4.3$ [[ "" -eq 0 ]] && echo "YES"
YES

Como você pode ver, não há erros e é realmente avaliado como expressão numérica com "" sendo igual a 0. Então, o que exatamente está acontecendo aqui? O [[ está simplesmente inconsistente com o antigo test ou POSIX? Ele está simplesmente realizando comparação de string em vez de comparação numérica?

    
por Sergiy Kolodyazhnyy 08.10.2017 / 22:04

2 respostas

11

Uma diferença entre [ e [[ é que [ não não faz avaliação aritmética, mas [[ faz:

$ [ "2 + 2" -eq 4 ] && echo yes
bash: [: 2 + 2: integer expression expected
$ [[ "2 + 2" -eq 4 ]] && echo yes
yes

A segunda sutileza é que, sempre que avaliação aritmética é executada no bash, as strings vazias são avaliadas como 0. Por exemplo:

$ x=""; echo $((0 + x))
0
$ [[ "" -eq 0 ]] && echo yes
yes

Documentação

De man bash :

Shell variables are allowed as operands; parameter expansion is performed before the expression is evaluated. Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax. A shell variable that is null or unset evaluates to 0 when referenced by name without using the parameter expansion syntax. The value of a variable is evaluated as an arithmetic expression when it is referenced, or when a variable which has been given the integer attribute using declare -i is assigned a value. A null value evaluates to 0. A shell variable need not have its integer attribute turned on to be used in an expression. [Emphasis added]

Além de: Problemas de segurança

Observe que a avaliação aritmética de bash é um possível problema de segurança. Por exemplo, considere:

x='a[$(rm -i *)]'
[[ x -eq 0 ]] && echo yes

Com a opção -i , o acima é seguro, mas a lição geral é não usar a avaliação aritmética de bash com dados não higienizados.

Por outro lado, com [ , nenhuma avaliação aritmética é executada e, conseqüentemente, o comando nunca tenta excluir arquivos. Em vez disso, gera um erro com segurança:

$ x='a[$(rm -i *)]'
$ [ x -eq 0 ] && echo yes
bash: [: x: integer expression expected

Para saber mais sobre esse problema, consulte esta resposta .

    
por 08.10.2017 / 22:18
2

Sim, o teste posix ( [ ) não converteria uma string em um número em comparações numéricas:

$ sh -c '[ 2+2 -eq 4 ]'
sh: 1: [: Illegal number: 2+2

$  dash -c '[ 2+2 -eq 4 ]'
dash: 1: [: Illegal number: 2+2

$ bash -c '[ 2+2 -eq 4 ] && echo "YES"'
bash: line 0: [: 2+2: integer expression expected

No entanto, nem todos os shells funcionam da mesma maneira:

$ ksh -c '[ 2+2 -eq 4 ] && echo "YES"'
YES

Solução normal

Certifique-se de que um valor nulo ou vazio seja convertido em 0 (funciona na maioria dos shells)

$ dash -c 'a=""; [ "${a:-0}" -gt 3 ] && echo "YES"'

Use aritmética

Use expansão aritmética (também pode converter valores como 2+2 em alguns shells (não traços))

$ dash -c 'a=""; [ "$((a+0))" -gt -3 ] && echo "YES"'
YES

Use [[

O uso do teste [[ converterá a maioria das sequências que se tornariam um número (mesmo que não desejado) em shells que permitem [[ :

$ [[ "2+2" -gt 3 ]] && echo "YES"
YES
    
por 09.10.2017 / 05:51