¿Es posible la expansión de parámetros en la expresión de prueba?

¿Es posible la expansión de parámetros en la expresión de prueba?

Cuando intento la siguiente expresión, bashaparece 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 -ltcon 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. -ltes 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, && truees 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 $IFSno se haya modificado su valor predeterminado.

Respuesta2

$(cmd)obtiene elsalida estándarde cmd¹, entonces para que eso se expanda al resultado, cmdnecesitasproducciónél:

some_func() {
  echo "$(( 3 + 5 ))"
}
[ "$(some_func)" -lt 10 ]

como ya han dicho otros. Sin embargo, eso significa some_funcque 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 countersolo 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 ksh93o zsh. bashno 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 ( $REPLYse 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 bashsus 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.

información relacionada