¿Cuál es la diferencia entre a[bc]d
y a{b,c}d
? ¿Por qué la gente usa a{b,c}d
cuando ya existe a[bc]d
?
ls
y solo prueba caracteres únicos, parecería que funcionan igual.
¿Cuál es la diferencia entre a[bc]d
y a{b,c}d
? ¿Por qué la gente usa a{b,c}d
cuando ya existe a[bc]d
?
ls
y solo prueba caracteres únicos, parecería que funcionan igual.
Respuestas:
Los dos son bastante diferentes.
a[bc]d
es un patrón de nombre de archivo (en shells que no sean fish
). Se expandirá a los dos nombres de archivo abd
y, acd
si son nombres de archivos existentes en el directorio actual.
La [...]
parte es una expresión entre corchetes que coincide con un solo carácter de los enumerados (o elementos de clasificación cuando se incluyen rangos). Para que coincida con el patrón a[bc]d
, el carácter entre las cadenas a
y d
en un nombre de archivo debe ser a b
o a c
.
Si abd
existe, pero acd
no existe, entonces solo se expandiría abd
y viceversa.
Si ninguno abd
, ni acd
existir, dependiendo de la cáscara y las opciones, que daría lugar a un error (Unix original sh
, (t)csh
, zsh
, fish
, bash -O failglob
) y posiblemente salir de la cáscara, o salir de la unexpanded¹ patrón (Bourne-como y rc
-como conchas) o ampliar a nada ( bash/zsh/yash -o nullglob
algunas versiones anteriores de fish
Unix original sh
y (t)csh
si hay otros globos coincidentes en el mismo comando).
a{b,c}d
es una expansión de llaves (en conchas que las admiten). Se expandirá a las dos cadenas abd
y acd
.
La {...}
parte es un conjunto delimitado por comas de cadenas (en este ejemplo, en algunos cáscara, también puede ser un intervalo tal como a..k
o 20..25
o más avanzadas que son como 00..20..2
o 0..20..2%02d
), y la expansión se calcula mediante la combinación de cada una de estas cadenas con el flanqueo cuerdas a
y d
. Estas cadenas podrían ser más largas que un solo personaje y también podrían ser expansiones de llaves.
La expansión ocurre independientemente de si estas cadenas corresponden a nombres de archivos existentes o no.
Si está construyendo cadenas, use una expansión de llaves. Si está haciendo coincidir nombres de archivo, use un patrón de nombre de archivo.
¹ En este caso particular, a[bc]d
podría ser el nombre de un archivo existente, por lo que es potencialmente peligroso usar cosas como rm -f ./*.[ch]
en esos shells y rm -f ./*.{c,h}
es un problema menor.
a{b,c}d
, las partes b
y c
no necesitan ser letras individuales; por ej ex{ten,ci}sion
. Mientras ex[tenci]sion
o lo que sea solo coincidirá con una de estas letras.
a[bc]d
es coincidencia de patrones y es parte del estándar POSIX. En POSIX, esto se introduce como la "expresión de paréntesis de patrón". Está documentado en la sección 2.13 del manual.
Cuando no están entre comillas y fuera de una expresión de paréntesis, los siguientes tres caracteres tendrán un significado especial en la especificación de patrones:
?
Un signo de interrogación es un patrón que debe coincidir con cualquier carácter.
* *Un asterisco es un patrón que debe coincidir con varios caracteres, como se describe en Patrones que coinciden con varios caracteres.
[El corchete abierto introducirá una expresión de corchete de patrón.
La Sección 2.13.3 también menciona algo que se comporta de manera diferente de lo que uno esperaría para las expresiones regulares habituales cuando se usa para la expansión de nombre de archivo (énfasis por mí)
Las reglas descritas hasta ahora en Patrones que coinciden con un solo carácter y Patrones que coinciden con varios caracteres se califican por las siguientes reglas que se aplican cuando la notación de coincidencia de patrones se utiliza para la expansión de nombre de archivo:
El carácter de barra diagonal en un nombre de ruta debe coincidir explícitamente utilizando una o más barras diagonales en el patrón; no debe coincidir con el asterisco o los caracteres especiales de signo de interrogación ni con una expresión entre corchetes. Las barras en el patrón se identificarán antes de las expresiones de paréntesis; por lo tanto, una barra inclinada no se puede incluir en una expresión de corchete de patrón utilizada para la expansión del nombre de archivo. Si se encuentra un carácter de barra diagonal después de un carácter de corchete abierto sin escape antes de encontrar un corchete de cierre correspondiente, el corchete abierto se tratará como un carácter ordinario. Por ejemplo, el patrón
"a[b/c]d"
no coincide con nombres de ruta comoabd
oa/d
. Solo coincide con un nombre de ruta de literalmentea[b/c]d
.
a{b,c}d
es una expansión de llaves , no está en la especificación de POSIX. Aquí está la parte correspondiente del manual de bash (énfasis por mí):
La expansión de llaves es un mecanismo por el cual se pueden generar cadenas arbitrarias . Este mecanismo es similar a la expansión de nombre de archivo (ver Expansión de nombre de archivo), pero los nombres de archivo generados no necesitan existir . Los patrones que se van a expandir entre paréntesis toman la forma de un preámbulo opcional , seguido de una serie de cadenas separadas por comas o una expresión de secuencia entre un par de paréntesis, seguido de una posdata opcional . El preámbulo tiene el prefijo de cada cadena contenida dentro de las llaves, y la posdata se agrega a cada cadena resultante, expandiéndose de izquierda a derecha.
Según el comentario de @mosvy, esto apareció por primera vez, csh
pero el comportamiento bash
es diferente csh
y de otros shells. Este tipo de expansión de llaves también está presente en glob(3)
.
Hay otro tipo de expansión de llaves {a..z}
que solo apareció después de bash
3.0, y hay más agregadas en bash
4.0.
En un shell donde está activado el globbing, ejecutar en una carpeta vacía, se devuelve el siguiente resultado
$ echo a[bc]d
a[bc]d
$ echo a{b,c}d
abd acd
En respuesta al comentario de @ Jesse_b, si estás en un shell interactivo y ambos aplican, a[bc]d
es menos difícil escribir. Por ejemplo grep pattern [ab][12].txt
.
csh
, mucho antes bash
. También está presente en la función de biblioteca glob (3). La diferencia es que bash
se realiza antes de otras expansiones: a=A; ab=A/B; ac=A/C; echo $a{b,c}
funcionará en bash de manera diferente a cualquier otro shell.
command a[bc]d
?