Quando tento a seguinte expressão, bash
recebo uma mensagem de erro estranha:
[: -lt: unary operator expected
Primeiro a definição da função
some_func () {
(( 3 + 5 ))
}
E a expressão
[ $(some_func) -lt 10 ] && true
Acho que o problema é misturar operadores como -lt
substituição de comando e/ou expansão aritmética?
O código de saída $?
é 2 e a mensagem éan unary op was expected
.
Responder1
Deveria ser
some_func() {
echo "$(( 3 + 5 ))"
}
[ "$(some_func)" -lt 10 ]
Por que falhou
$(some_func)
se expande para osaídada função* (menos a nova linha final), que, no entanto, não produz nada. Portanto, o teste torna-se
[ -lt 10 ]
Nas suas formas mais básicas,o [
teste aceita 1 a 3 parâmetros. Como acima existem 2 parâmetros, o Bash espera que o primeiro seja um operador unário. -lt
é binário, daí a mensagem de erro.
Você tinhacitou a expansão conforme apropriadocom
[ "$(some_func)" -lt 10 ]
O erro seria "expressão inteira esperada" porque o teste teria a string vazia:
[ "" -lt 10 ]
E, a menos que sobcircunstâncias não triviais, && true
é redundante.
*Como a expansão não está cotada, a produção também sofredivisão de palavraseexpansão do nome do arquivo. Eles não devem desempenhar um papel no presente exemplo, desde que $IFS
seu valor padrão não tenha sido alterado.
Responder2
$(cmd)
recebe osaída padrãode cmd
¹, então para que isso se expanda para o resultado, você cmd
precisasaídaisto:
some_func() {
echo "$(( 3 + 5 ))"
}
[ "$(some_func)" -lt 10 ]
como outros já disseram. No entanto, isso significa que some_func
é executado em um ambiente subshell, portanto, qualquer modificação nas variáveis ou qualquer outra coisa será perdida posteriormente.
Por exemplo, não adianta fazer:
counter=0
incr() { echo "$((++counter))"; }
while [ "$(incr)" -le 10 ]...
as $(incr)
sempre será expandido para 1 (as counter
só será incrementado no subshell).
Para que uma função retorne um resultado numérico por meio de umavaliação aritmética, você precisaria de um shell com suporte parafunções matemáticascomo ksh93
ou zsh
. bash
não servirá.
Em zsh
:
counter=0
incr() (( ++counter ))
functions -M incr
while (( incr() <= 10 )); do
print $counter
done
Em ksh93
:
function .sh.math.incr i {
# ksh93 functions must take at least one argument
(( .sh.value = (counter += i) ))
}
while (( incr(1) <= 10 )); do
print "$counter"
done
Outra alternativa no ksh93 ou em versões recentes do mksh é usar formas de substituição de comando que não introduzam subshells:
counter=0
function incr { print "$(( ++counter ))"; }
while [ "${ incr; }" -le 10 ]; do
print "$counter"
done
Ou em mksh
:
counter=0
incr() (( REPLY = ++counter ))
while [ "${| incr; }" -le 10 ]; do
print "$counter"
done
Em qualquer shell POSIX incluindo bash
, você sempre pode retornar o valor em uma variável predefinida ( $REPLY
é comumente usada para isso):
counter=0
incr() { REPLY=$(( counter += 1 )); }
while incr; [ "$REPLY" -le 10 ]; do
echo "$counter"
done
Você encontrará mais detalhes emesta resposta para outra pergunta e resposta sobre o recurso valsub do mksh
¹ sem seus caracteres de nova linha finais e, no caso de bash
seus caracteres NUL, e aqui porque você esqueceu as aspas, sujeito a split + glob
Responder3
Substituição de comandocaptura a saídade um comando ou função. Essa função não tem saída.
A $?
variável contém oCódigo de retornoda função.
Faça isso:
some_func
(( $? < 10 )) && echo yes
ou altere a função para:
some_func() {
echo $(( 3 + 5 ))
}
[[ $(some_func) -lt 10 ]] && echo yes
Observe como estou usando [[...]]
em vez de [...]
? A condicional de colchete duplo é mais indulgente com valores vazios.