Cuando intento la siguiente expresión, bash
aparece un mensaje de error extraño:
[: -lt: unary operator expected
Primero la definición de la función.
some_func () {
(( 3 + 5 ))
}
y la expresión
[ $(some_func) -lt 10 ] && true
Supongo que el problema es mezclar operadores como -lt
con la sustitución de comandos y/o la expansión aritmética.
El código de salida $?
es 2 y el mensaje esan unary op was expected
.
Respuesta1
Debería ser
some_func() {
echo "$(( 3 + 5 ))"
}
[ "$(some_func)" -lt 10 ]
Por qué falló
$(some_func)
se expande a laproducciónde la función* (menos su nueva línea final), que sin embargo no genera nada. Por lo tanto, la prueba se convierte
[ -lt 10 ]
En sus formas más básicas,la [
prueba acepta de 1 a 3 parámetros. Como arriba hay 2 parámetros, Bash espera que el primero sea un operador unario. -lt
es binario, de ahí el mensaje de error.
¿Tuvistecitó la expansión como apropiadacon
[ "$(some_func)" -lt 10 ]
El error sería "se espera una expresión entera" porque la prueba tendría la cadena vacía:
[ "" -lt 10 ]
Y, a menos que bajocircunstancias no triviales, && true
es redundante.
*Dado que la expansión no está cotizada, la producción también sufredivisión de palabrasyexpansión de nombre de archivo. Estos no deberían desempeñar un papel en el presente ejemplo, siempre y cuando $IFS
no se haya modificado su valor predeterminado.
Respuesta2
$(cmd)
obtiene elsalida estándarde cmd
¹, entonces para que eso se expanda al resultado, cmd
necesitasproducciónél:
some_func() {
echo "$(( 3 + 5 ))"
}
[ "$(some_func)" -lt 10 ]
como ya han dicho otros. Sin embargo, eso significa some_func
que se ejecuta en un entorno de subshell, por lo que cualquier modificación de las variables o cualquier otra cosa se perderá posteriormente.
Por ejemplo, no tiene sentido hacer:
counter=0
incr() { echo "$((++counter))"; }
while [ "$(incr)" -le 10 ]...
as $(incr)
siempre se expandirá a 1 (as counter
solo se incrementará en la subcapa).
Para que una función devuelva un resultado numérico a través de unevaluación aritmética, necesitarías un shell con soporte parafunciones matemáticascomo ksh93
o zsh
. bash
no lo haré.
En zsh
:
counter=0
incr() (( ++counter ))
functions -M incr
while (( incr() <= 10 )); do
print $counter
done
En 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
Otra alternativa en ksh93 o versiones recientes de mksh es usar formas de sustitución de comandos que no introduzcan subshells:
counter=0
function incr { print "$(( ++counter ))"; }
while [ "${ incr; }" -le 10 ]; do
print "$counter"
done
O en mksh
:
counter=0
incr() (( REPLY = ++counter ))
while [ "${| incr; }" -le 10 ]; do
print "$counter"
done
En cualquier shell POSIX, incluido bash
, siempre puede devolver el valor en una variable predefinida ( $REPLY
se usa comúnmente para eso):
counter=0
incr() { REPLY=$(( counter += 1 )); }
while incr; [ "$REPLY" -le 10 ]; do
echo "$counter"
done
Encontrarás más detalles enesta respuesta a otra pregunta y respuesta sobre la función valsub de mksh
¹ despojado de sus caracteres de nueva línea finales, y en el caso de bash
sus caracteres NUL, y aquí porque olvidó las comillas, sujeto a split+glob
Respuesta3
Sustitución de mandocaptura la salidade un comando o función. Esa función no tiene salida.
La $?
variable contiene lacódigo de retornode la función.
O haz esto:
some_func
(( $? < 10 )) && echo yes
o cambiar la función a:
some_func() {
echo $(( 3 + 5 ))
}
[[ $(some_func) -lt 10 ]] && echo yes
¿Observas cómo estoy usando [[...]]
en lugar de [...]
? El condicional de doble corchete es más indulgente con los valores vacíos.