¿Qué es la expansión indirecta? ¿Qué significa $ {! Var *}?

85

Estoy leyendo " Guía de Bash para principiantes ". Dice:

Si el primer carácter de PARAMETERes un signo de exclamación, Bash usa el valor de la variable formada a partir del resto de PARAMETERcomo el nombre de la variable; esta variable luego se expande y ese valor se usa en el resto de la sustitución, en lugar del valor de PARAMETERsí mismo. Esto se conoce como expansión indirecta.

El ejemplo dado es:

franky ~> echo ${!N*}
NNTPPORT NNTPSERVER NPX_PLUGIN_PATH

No entiendo bien aquí:

el valor de la variable formada por el resto de PARAMETER

Como PARAMETERes justo !N*, entonces

el resto de PARAMETER

es justo N*. ¿Cómo podría esto formar una variable? ¿Bash buscó todos los comandos posibles allí?

athos
fuente

Respuestas:

110

Si lee la bashpágina del manual, básicamente confirma lo que ha dicho:

Si el primer carácter del parámetro es un signo de exclamación ( !), se introduce un nivel de direccionamiento indirecto variable. Bash usa el valor de la variable formada a partir del resto del parámetro como el nombre de la variable; esta variable luego se expande y ese valor se usa en el resto de la sustitución, en lugar del valor del parámetro en sí. Esto se conoce como expansión indirecta.

Sin embargo, leyendo desde allí:

Las excepciones a esto son las expansiones de ${!prefix*}y se ${!name[@]}describen a continuación.

${!prefix*}Nombres coincidentes con prefijo. Se expande a los nombres de las variables cuyos nombres comienzan con prefijo, separados por el primer carácter de la IFSvariable especial.

En otras palabras, su ejemplo particular ${!N*}es una excepción a la regla que citó. Se hace , sin embargo, funcionan como se anuncia en los casos previstos, tales como:

$ export xyzzy=plugh ; export plugh=cave

$ echo ${xyzzy}  # normal, xyzzy to plugh
plugh

$ echo ${!xyzzy} # indirection, xyzzy to plugh to cave
cave
paxdiablo
fuente
1
Gracias por la respuesta. Cuanto más leo la "Guía de Bash para principiantes", más me pregunto si la autora comprende lo que escribe.
LRDPRDX
23

Parece haber una excepción cuando la "indirección" dada termina en a *, como ocurre aquí. En este caso, da todos los nombres de variables que comienzan con la parte que especificó ( Naquí). Bash puede hacer eso porque rastrea las variables y sabe cuáles existen.

La verdadera indirección es la siguiente:
digamos que tengo una variable $VARIABLEestablecida en 42y tengo otra variable $NAMEestablecida en VARIABLE. ${!NAME}me dará 42. Utiliza el valor de una variable para decirle el nombre de otra:

$ NAME="VARIABLE"
$ VARIABLE=42
$ echo ${!NAME}
42
Kevin
fuente
5
¡Vaya, quién diría que era tan fácil obtener la respuesta al significado de la vida, el universo y todo!
KomodoDave
3

Sí, busca todas las posibles expansiones de variables después de!. Si lo hubiera hecho:

echo ${!NP*}

solo obtendrías NPX_PLUGIN_PATH .

Considere el siguiente ejemplo:

:~> export myVar="hi"
:~> echo ${!my*}
    myVar
:~> export ${!my*}="bye"
:~> echo $myVar
    bye
tpg2114
fuente
¿otras variables que coincidan con mi * también se establecerían en "bye"?
Anthony
1
@Anthony Lo probé, y si se ${!my*}expande a myA, myB, myA se exporta con su valor actual y myB se establece en "bye" y se exporta. No es muy útil.
GKFX
3

Ha encontrado una excepción en el procesamiento indirecto, donde si el último carácter es *, se devolverán todas las variables que tienen el prefijo dado antes.

Ignacio Vázquez-Abrams
fuente
Entonces, aparte del *caso, ¿es esto lo mismo que ${${VAR}}?
chronospoon
1
@chronospoon, ${${VAR}}más brevemente escribible como ${$VAR}, no es legal, ya que $VARdevuelve una cadena, que no puede seguir el $signo; para usar una cadena como nombre de variable, debe introducir un nivel de direccionamiento indirecto (como se cita en la pregunta original), es decir , puede usar ${!VAR}, que hace exactamente lo que esperaría (errónea pero comprensiblemente) ${$VAR}.
Enrico