¿Cuál es la diferencia entre `a [bc] d` (corchetes) y` a {b, c} d` (llaves)?

28

¿Cuál es la diferencia entre a[bc]dy a{b,c}d? ¿Por qué la gente usa a{b,c}dcuando ya existe a[bc]d?

Weijun Zhou
fuente
¿Quién te dijo que usaras command a[bc]d?
Jesse_b
3
Ciertamente tiene sus usos si uno lo entiende correctamente.
Weijun Zhou
77
Supongo que no entiendo cómo ocurrió la confusión entre los dos.
Jesse_b
Un compañero de trabajo menos familiarizado con Linux me ha preguntado explícitamente sobre esto, aunque no recientemente.
Weijun Zhou
@Jesse_b Si solo los prueba con operaciones en archivos como lsy solo prueba caracteres únicos, parecería que funcionan igual.
Nacht - Restablece a Monica el

Respuestas:

43

Los dos son bastante diferentes.

a[bc]des un patrón de nombre de archivo (en shells que no sean fish). Se expandirá a los dos nombres de archivo abd y, acdsi 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 ay den un nombre de archivo debe ser a bo a c.

  • Si abdexiste, pero acdno existe, entonces solo se expandiría abdy viceversa.

  • Si ninguno abd, ni acdexistir, 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 nullglobalgunas versiones anteriores de fishUnix original shy (t)cshsi hay otros globos coincidentes en el mismo comando).

a{b,c}des 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..ko 20..25o más avanzadas que son como 00..20..2o 0..20..2%02d), y la expansión se calcula mediante la combinación de cada una de estas cadenas con el flanqueo cuerdas ay 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]dpodrí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.

Kusalananda
fuente
Gracias por aclarar "Si abd existe, pero acd no, entonces solo se expandiría a abd". Supongo que eso es lo que falta en mi respuesta.
Weijun Zhou
9
Otra diferencia crucial es que en a{b,c}d, las partes by cno necesitan ser letras individuales; por ej ex{ten,ci}sion. Mientras ex[tenci]siono lo que sea solo coincidirá con una de estas letras.
alexis
7

a[bc]des 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 como abdo a/d. Solo coincide con un nombre de ruta de literalmente a[b/c]d.

a{b,c}des 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, cshpero el comportamiento bashes diferente cshy 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 bash3.0, y hay más agregadas en bash4.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]des menos difícil escribir. Por ejemplo grep pattern [ab][12].txt.

Weijun Zhou
fuente
2
La expansión del aparato ortopédico no es un "bashismo"; apareció por primera vez csh, mucho antes bash. También está presente en la función de biblioteca glob (3). La diferencia es que bashse 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.
mosvy
Gracias. Actualizaré la respuesta.
Weijun Zhou