Diferencia entre expansión y sustitución en terminología de scripting de shell

8

La expansión y la sustitución parecen ser intercambiables en el mismo contexto en el lenguaje de programación de shell. Por ejemplo, algunos documentos como el manual de referencia de Bash , Bash Hackers Wiki usan la palabra 'expansión' para explicar ' expansión de parámetros de shell '. Sin embargo, algunos otros documentos parecen preferir la palabra 'sustitución'. La Guía avanzada de secuencias de comandos Bash utiliza la sustitución de parámetros .

¿Hay alguna diferencia entre 'expansión' y 'sustitución' en términos de terminología de programación de shell?

MS.Kim
fuente
Ambos son válidos en diferentes contextos, por ejemplo variable expansion, command substitution. Cual es tu duda
devnull
Sin un contexto específico, me temo que esto es demasiado amplio y poco claro también.
devnull
Al mirar la página de manual de bash, en general, la palabra "expansión" parece usarse si solo están involucradas cosas internas del shell, mientras que la "sustitución" parece ser preferida para cosas que involucran procesos externos.
celtschk
Si sigue mi consejo, dejará de leer esos documentos hasta que esté completamente familiarizado con estos: pubs.opengroup.org/onlinepubs/9699919799/utilities/… Cuando haya terminado con los que hace man shy man set. Y cuando tienes esas cosas, entonces haces los documentos específicos de shell.
mikeserv
@devnull Tienes razón. Aunque puse el enlace para el contexto, sería mejor especificar el contexto explícitamente con una pregunta. Editaré la pregunta para que la gente pueda entenderla claramente.
MS.Kim

Respuestas:

6

La sustitución es casi sinónimo de expansión en este contexto porque sus significados se superponen. Ninguno de los dos es una subcategoría bastante completa del otro, aunque en la sección del Manual de GNU a la que hace referencia hay sustituciones que se consideran parte de una expansión general.

Una expansión es extraer el valor de un identificador. Por ejemplo, si this=that, cuando nos expandimos this, obtenemos that. Una expansión que no implica sustitución está predeterminada porque el valor utilizado ya existe y simplemente debe recuperarse, aunque esto incluye combinar valores recuperados / explícitos (como con "expansión aritmética").

Una sustitución crea un valor como resultado de una operación explícita de entrada / salida. Por ejemplo, si this=$(foo bar), thises el resultado de ejecutar foo bary capturar su salida. 1 Aunque el valor resultante de una sustitución puede ser completamente predecible, es diferente del obtenido en una expansión normal porque en realidad no existe hasta que se lleva a cabo la sustitución: se produce.

Las sustituciones vienen en dos sabores, comando y proceso , que son algo simétricos:

# Command substitution
foo=$(ls)
# Process substitution
wc <(ls)

El "comando" en el primero es ls, al igual que el "proceso" en el segundo. Podríamos decir que lo que se está sustituyendo es realmente el final de una tubería. La sustitución del proceso se superpone con la redirección . Sin embargo, esto es técnicamente demasiado restrictivo, lo que nos lleva a la nota al pie ...


  1. foo baren este caso podría ser una función de shell interna, en cuyo caso no hay E / S entre procesos. La existencia de funciones integradas de shell oscurece menos esta diferencia. En términos de contenido, la entrada y la salida serán las mismas.
encerrada dorada
fuente
Me gusta esta explicación, pero ¿cómo se cuadraría con la expansión del nombre de archivo , que ciertamente produce un conjunto de nombres de archivo como resultado de una operación (un algoritmo de coincidencia).
De Novo
Claro, pero para jugar semántica, ¿no es "extraer el valor de un identificador" (lo que he llamado una expansión) también una operación, por lo tanto, una sustitución? Sobre todo porque "hay sustituciones que se consideran parte de una expansión general". Es decir, la relación entre estas palabras no es análoga a la distinción entre izquierda y derecha. Creo que la expansión de nombre de archivo se ajusta bien a mi definición original de expansión, pero he aclarado las cosas sobre las sustituciones anteriores para ayudar a que sea más obvio por qué no es eso.
Ricitos de oro
El problema que tuve al cuadrar esta explicación intuitiva con la expansión del nombre de archivo no fue que quisiera que los términos se definieran exclusivamente, sino que la expansión del nombre de archivo no parece recuperar un valor vinculado a un identificador. Dentro de un shell determinado, el valor de un glob determinado dependería de algo más que el glob, y el mismo glob podría producir diferentes resultados en diferentes contextos. Además, no es necesario vincular el valor para recuperarlo más tarde. La relación no es arbitraria (como en foo = "lo que quieras"; echo "$ foo"), sino más bien cálculo y resultado.
De Novo
Supongo que la relación entre expresión y valor en la expansión aritmética tampoco es (exactamente) arbitraria, pero definitivamente solo hay un valor para una expansión dada, independientemente del contexto. Es posible que solo esté siendo quisquilloso aquí, pero de todas las expansiones de shell, la expansión de nombre de archivo parece ser el hombre extraño, dada esta explicación.
De Novo
2
set -- arg arg2
echo ${2+"$1"}
 #OUTPUT 
arg

shift
echo ${2+"$1"}
 #OUTPUT

 #there doesn't seem to be anything here

Creo que la diferencia es generalmente mínima para ser notoria, y los términos a menudo se usan indistintamente. Sin embargo, si nos fijamos en las anteriores dos casos, se puede ver que en el primer ejemplo nos sustituto $1 para $2, como resultado de la expansión de $2. Tan pronto como $2no se puede ampliar, no hay sustitución.

Ricitos de oro hace un buen punto sobre la existencia etérea de sustituciones. Como el gato de Schrodinger, supongo. Me recordó algo. Es posible que no esté familiarizado con esta forma de expansión de parámetros especificada por POSIX, pero funciona de forma opuesta a la forma anterior:

${var:?if $var is unset or null its \
     parent shell dies and this message is output to stderr}

Ahora a veces quiero el mismo comportamiento pero por un setvalor. POSIX no especifica ese comportamiento para nada exactamente. Pero, con un truco o dos, simplemente se gestiona:

N= #N is null
var="any value should fail"
${var:+${N:?we substitute our \$Null var when \$var is expanded}}
  #OUTPUT
sh: line 3: N: we substitute our $Null var when $var is expanded

Pero:

N= #N is null
var=
${var:+${N:?is never substituted}}
  #OUTPUT

#there doesn't seem to be anything here
mikeserv
fuente