Bash: expansión aritmética, expansión de parámetros y operador de coma

Bash: expansión aritmética, expansión de parámetros y operador de coma

Tengo una pregunta sobre la expansión de parámetros de bash, dentro de una expresión de coma, dentro de una expresión aritmética. Tengo dos declaraciones que pensé que deberían ser equivalentes, pero no lo son.

¿Por qué la línea bash

n=3; k=10; echo $((n++,k=$n))

salida 3en lugar de 4? (Se establece nen 4, como esperaba, pero se establece ken 3).

Por el contrario, la línea bash

 n=3; k=10; echo $((n++,k=n))

salidas 4, como esperaba. (Se establece nen 4y ktambién 4).

Intenté reemplazar n++con ++n, con n=n+1y con n=$((n+1))en ambas líneas bash, y todas producen la misma discrepancia: k=$nproduce 3en todos los scripts y k=nproduce 4en todos ellos.


Tengo entendido que, si el valor de nes un número entero (que lo es), $ndebería ntener el mismo valor dentro de una expresión aritmética. (Y esta es una expresión aritmética debido a la (( ... ))construcción). Según el manual de bash, en la sección Evaluación aritmética, en una expresión aritmética:

   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.

Entonces, ¿por qué bash se trata $nde manera diferente a la nde este ejemplo y exactamente cómo se evalúa $n?


No pude duplicar el problema sin usar el operador de coma. El operador de coma, por lo que siempre he visto, calcula cada una de las subexpresiones de sus componentes de izquierda a derecha, incluidos todos los efectos secundarios de cada componente cuando se calcula ese componente. El valor de la expresión de coma es entonces el valor del último componente calculado (el que está más a la derecha).


Esta pregunta surgió en el contexto de un guión mucho más complicado y finalmente la reduje a este ejemplo simple que demuestra el problema.

Entonces, ¿qué estoy entendiendo mal acerca de la expansión aritmética, la expansión de parámetros o el operador de coma?

Tenga en cuenta que no estoy buscando una solución alternativa, ya que ya tengo una: la versión con nen lugar de $nfunciona como esperaba. Solo quiero entender qué hace bash en la versión con $n, y por qué hace algo diferente a la versión con solo n.

Respuesta1

Se produce la expansión de los parámetros de Shellantes de que se evalúe la expresión, incluido el manejo de comas:

La expresión se trata como si estuviera entre comillas dobles, pero las comillas dobles entre paréntesis no se tratan de forma especial. Todos los tokens de la expresión se someten a expansión de parámetros y variables, sustitución de comandos y eliminación de comillas. El resultado se trata como la expresión aritmética a evaluar.

Puedes ver esto con

unset n
echo $((n++,k=$n))

El mensaje de error,

bash: n++,k=: syntax error: operand expected (error token is "=")

muestra que $nse reemplaza antes de que se maneje toda la expresión aritmética.

En su caso, la expresión que se evalúa es

n++,k=3

Respuesta2

En el interior $((...)), la expansión se realiza primero¹ como si estuviera entre comillas dobles, y luego se evalúa el resultado.

Entonces, en n=3; k=10; echo $((n++,k=$n))(o n=1; echo "$((++n + $n))", eso no se limita a ,), la expresión aritmética que se evalúa es n++, k=3.

Aquí necesitas:

n=3; k=10; echo "$((n++,k=n))"

(también tenga en cuenta las comillas, ya que la expansión aritmética está sujeta a split+glob como otras formas de expansiones de palabras en shells POSIX).


¹, encontrará alguna variación en la que se invocan matrices y matrices asociativas, ya que algunos shells intentarán manejar $((hash[$key]++))correctamente cuando $keycontiene ], por ejemplo

información relacionada