He notado que {
se puede usar en la expansión de llaves:
echo {1..8}
o en la agrupación de comandos:
{ls;echo hi}
¿Cómo sabe bash la diferencia?
bash
shell-script
primavera amorosa
fuente
fuente
{
interpretarse como una lista de comandos si aparece al comienzo de un comando y, de lo contrario, como una expansión de llaves, pero no estoy seguro.{ls;echo hi}
No es legalbash
. Necesita un espacio después de la llave de apertura y un punto y coma antes de la de cierre.Respuestas:
Una razón simplificada es la existencia de un carácter: space.
Las expansiones de llaves no procesan espacios (sin comillas).
Una
{...}
lista necesita espacios (sin comillas).La respuesta más detallada es cómo el shell analiza una línea de comando .
El primer paso para analizar (comprender) una línea de comando es dividirla en partes.
Estas partes (generalmente llamadas palabras o tokens) resultan de dividir una línea de comando en cada metacarácter del enlace :
Metacaracteres: spacetabenter;,<>|y &.
Después de dividir, las palabras pueden ser de un tipo (tal como lo entiende el shell):
LC=ALL ...
LC=ALL echo
LC=ALL echo "hello"
LC=ALL echo "hello" >&2
Expansión de la llave
Solo si una "cadena de llaves" (sin espacios o metacaracteres) es una sola palabra (como se describe anteriormente) y no se cita , es un candidato para la "expansión de llaves". Más controles se realizan en la estructura interna más adelante.
Por lo tanto, esto:
{ls,-l}
califica como "expansión de llaves" para convertirsels -l
, ya sea comofirst word
oargument
(en bash, zsh es diferente).Pero esto no:
{ls ,-l}
. Bash se dividirá spacey analizará la línea como dos palabras:{ls
y,-l}
que activará acommand not found
(,-l}
se pierde el argumento ):Su línea:
{ls;echo hi}
no se convertirá en una "expansión de llaves" debido a los dos metacaracteres ;y space.Se divide en tres partes esta:
{ls
nuevo comando:echo
hi}
. Comprenda que ;desencadena el inicio de un nuevo comando. El comando{ls
no se encuentra, y el siguiente comando imprimiráhi}
:Si se coloca después de algún otro comando, de todos modos comenzará un nuevo comando después de ;:
Lista
Uno de los "comandos compuestos" es una "Lista Brace" (mis palabras):
{ list; }
.Como puede ver, se define con espacios y un cierre
;
.Los espacios y ;son necesarios porque ambos
{
y}
son " palabras reservadas ".Y por lo tanto, para ser reconocido como palabras, debe estar rodeado de metacaracteres (casi siempre:) space.
Como se describe en el punto 2 de la página vinculada
Tu ejemplo:
{ls;echo hi}
no es una lista.Necesita un cierre ;y un espacio (al menos) después {. El último }está definido por el cierre ;.
Esta es una lista
{ ls;echo hi; }
. Y esto{ ls;echo hi;}
también es (menos utilizado, pero válido) (Gracias @choroba por la ayuda).Pero como argumento (el shell conoce la diferencia) a un comando, desencadena un error:
Pero tenga cuidado con lo que cree que el shell está analizando:
fuente
;
y}
.{ ls;}
funciona ya que el punto y coma ya es un meta-personaje.El bloque
{
es una palabra clave de shell, por lo que debe estar separado de la siguiente palabra por espacio, mientras que en la expansión de llaves, no debe haber espacio (si necesita llaves para expandir un espacio, debe escapar de élecho {\ ,a}{b,c}
).Puede usar la expansión de llaves al comienzo de un comando:
Sin embargo, no puede usarlo para expandir a un bloque, ya que el análisis de los comandos de agrupación ocurre antes de las expansiones:
fuente
Lo sabe comprobando la sintaxis de la línea de comando. Del mismo modo, sabe que en la expresión
echo echo
, el primer eco debe tratarse como un comando y el segundo eco como un parámetro del primer eco.En bash es muy simple, ya que
{ cmd; }
debe tener espacios y punto y coma. Sin embargo, por ejemplo, en zsh no son necesarios, pero aún analizando el contexto de{}
shell es capaz de decir qué se debe hacer con su contenido.Considera lo siguiente:
Ambos devuelven la fecha actual, pero
devuelve
1 2 3
porque shell conoce{}
en un argumento para comandoecho
, por lo que debe expandirse.fuente
{
seguido de un espacio sin comillas no comienza la expansión de llaves en bash.{
. El espacio sin comillas no puede estar en ninguna parte porque el shell divide toda la línea de comando en los espacios.En primer lugar, una llave compuesta debe ser una palabra en sí misma y la primera palabra de la línea de comando:
En segundo lugar, los brackets individuales no son especiales (como puede ver arriba). Las llaves vacías tampoco son especiales:
Cualquier cosa sin comas también es solo
Aquí es donde comienza la acción.
Entonces, básicamente, para que se inicie la expansión de llaves, necesitamos una sola palabra (no separada en campos en el espacio en blanco), dentro de la cual se produce al menos una instancia de
{...}
dentro de la cual se produce al menos una coma.Esta puede ser la primera palabra en la línea de comando, por cierto:
fuente