diferencia entre $ {} y $ () en el script de shell


Respuestas:


39

$(command)es "sustitución de comando". Como parece entender, ejecuta command, captura su salida e inserta eso en la línea de comando que contiene el $(…); p.ej,

$ ls -ld $(date +%B).txt
-rwxr-xr-x  1 Noob Noob    867 Jul  2 11:09 July.txt

${parameter}es "sustitución de parámetros". Se puede encontrar mucha información en la página de manual del shell, bash (1) , bajo el encabezado " Expansión de parámetros ":

${parameter}
    El valor del parámetro se sustituye. Las llaves se requieren cuando el parámetro es un parámetro posicional con más de un dígito, o cuando el parámetro va seguido de un carácter que no debe interpretarse como parte de su nombre.

Para los parámetros posicionales, consulte " Parámetros posicionales ", a continuación. En su uso más común, como se muestra en las otras respuestas, parameteres un nombre de variable. El ${…}formulario, como se indica al final del párrafo anterior, le permite obtener el valor de una variable (es decir, ) y seguirlo inmediatamente con una letra, dígito o guión bajo:$variable_name

$ animal = gato
$ echo $ animales
                                # No hay variables como "animales".
$ echo $ {animal} s
gatos
$ echo $ animal_food
                                # No existe una variable como "animal_food".
$ echo $ {animal} _food
comida de gato

También puedes hacer esto con citas:

$ echo "$ animal" s
gatos

O, como ejercicio de opciones, podría usar una segunda variable:

$ plural = s
$ echo $ animal $ plural
gatos

Pero esto es solo el paso 1. El siguiente párrafo en la página del manual es interesante, aunque un poco críptico:

Si el primer carácter del parámetro es un signo de exclamación ( !), se introduce un nivel de indirección variable. Bash usa el valor de la variable formada a partir del resto del parámetro como el nombre de la variable; esta variable 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 .     ... (excepciones) ...    El signo de exclamación debe seguir inmediatamente a la llave izquierda para introducir la indirección.

No estoy seguro de cómo puedo aclarar esto, excepto por ejemplo:

$ animal = gato
$ echo $ animal
gato
$ cat = tabby
$ echo $ cat
atigrado
$ echo $ {! animal}
tabby                            # Si $ animal es "gato" , entonces $ {! animal} es $ gato , es decir, "tabby"

Entonces llamemos a ese paso 1½. Hay muchas cosas interesantes que puedes hacer como paso 2:

$ animal = gato
$ echo $ {# animal}
3                                # longitud de cadena
$ echo $ {animal / at / ow}
vaca                              # Sustitución

No puedes hacer ninguna de esas cosas sin los {... }aparatos ortopédicos.

Parámetros Posicionales

Considere este ejemplo artificial :

$ gato myecho.sh
echo $ 1 $ 2 $ 3 $ 4 $ 5 $ 6 $ 7 $ 8 $ 9 $ 10 $ 11 $ 12 $ 13 $ 14 $ 15
$ ./myecho.sh Hey diddle diddle, El gato y el violín, La vaca saltó sobre la luna.
Hey diddle diddle, El gato y el violín, The Hey0 Hey1 Hey2 Hey3 Hey4 Hey5

debido a que la cáscara no entiende $10, $11etc. Se trata $10como si fuera ${1}0. Pero sí comprende ${10}, ${11}etc., como se menciona en la página del manual ("un parámetro posicional con más de un dígito").

Pero en realidad no escriba guiones como ese; Hay mejores maneras de lidiar con largas listas de argumentos.

Lo anterior (junto con muchas más formas de construcciones) se discuten con mayor detalle en la página de manual del shell, bash (1) .${parameter…something_else}

Una nota sobre cotizaciones

Tenga en cuenta que siempre debe citar las variables de shell a menos que tenga una buena razón para no hacerlo y esté seguro de saber lo que está haciendo. Por el contrario, aunque las llaves pueden ser importantes, no son tan importantes como las comillas.

$ filename = "rima infantil.txt"
$ ls -ld $ {filename}
ls: no se puede acceder a la guardería: no existe tal archivo o directorio
ls: no se puede acceder a rhyme.txt: no existe tal archivo o directorio
$ ls -ld "$ nombre de archivo"
-rwxr-xr-x 1 Noob Noob 5309 2 de julio 11:09 rima infantil.txt

Eso también se aplica a los parámetros posicionales (es decir, argumentos de línea de comandos; por ejemplo, "$1") y también a la sustitución de comandos:

$ ls -ld $ (fecha "+% B% Y"). txt
ls: no se puede acceder a julio: no existe tal archivo o directorio
ls: no se puede acceder a 2015.txt: no existe tal archivo o directorio
$ ls -ld "$ (fecha" +% B% Y "). txt"
-rwxr-xr-x 1 Noob Noob 687 2 de julio 11:09 de julio de 2015.txt

Ver cotizaciones del golpe sin escape en sustitución de comandos durante un breve tratado sobre la interacción entre las cotizaciones y $(... ).


Gracias por el maravilloso ejemplo. ¿Se puede elaborar el uso de! en tu ejemplo Realmente no entiendo cómo funciona.
Noob

@Noob: OK, desarrollé el uso de !.
G-Man dice 'reinstalar a Monica' el

Gracias. De alguna manera, animal se está refiriendo a la variable cat en lugar del valor cat. ¿También puede decirme cómo / at se convierte en una "c" en eco $ {animal / at / ow} La explicación del hombre de bash es de alguna manera ... no lo sé. difícil de entender.
Noob

Además, ¿puede elaborar esta frase: "$ {parámetro} El valor del parámetro se sustituye". sustituido con qué? si el parámetro es fruit y su valor es apple - fruit = apple, entonces $ {fruit} - ¿la manzana se sustituye con ?? realmente no entiendo el significado aquí
Noob

@Noob: "en ${!animal}realidad se refiere a la variable en $catlugar del valor cat". Sí, ese es exactamente el punto. “¿Cómo / at se convierte en una" c "en echo $ {animal / at / ow}?” ¿Huh? / at no se convierte en "c"; "Gato" se convierte en "vaca" cuando "at" se reemplaza por "ow".
G-Man dice 'Reincorporar a Monica' el

7

En su ejemplo, $ var y $ {var} son idénticos. Sin embargo, las llaves son útiles cuando desea expandir la variable en una cadena:

    $ string=foo
    $ echo ${string}bar
      foobar
    $ echo $stringbar

    $ 

Por lo tanto, las llaves proporcionan una forma de sustituir la variable para obtener el nombre de la nueva variable, que se sustituirá.


4

Por lo general, lo veo más comúnmente en cadenas. Algo como esto no funcionará:

var="a"
echo "$varRAW_STRING"

Pero esto:

var="a"
echo "${var}RAW_STRING"

Como dijiste correctamente, $()se usa para ejecutar un comando:

dir_contents=$(ls)

También puedes usar backticks, pero me parece el $()más versátil. Por un lado, los backticks no pueden (fácilmente) anidarse.

date_directory=`ls `date '+%Y-%m-%d'`` # Makes no sense
date_directory=$(ls $(date '+%Y-%m-%d')) # Much better

En realidad, acentos abiertos pueden ser anidados: date_directory=`ls \`date '+%Y-%m-%d'\``. Pero es terriblemente feo; $(…)Es mucho más claro y fácil de usar.
G-Man dice 'reinstalar a Monica' el

OK bastante justo. Es técnicamente posible, pero no puedo imaginar que alguien lo haga solo por la legibilidad
bytesizado el

1
Bueno, `…`fue la (única) sintaxis para la sustitución de comandos durante años antes de que $(…)se inventara, por lo que no necesita imaginar nada: la gente lo hizo.
G-Man dice 'reinstalar a Monica' el

s / alguna vez haciéndolo / haciéndolo más /
ocultó el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.