¿Qué hace `. []. Foo []` en bash? ¿Por qué coincide con `..`?

16

Mira lo siguiente:

$ echo .[].aliases[]
..
$ echo .[].foo[]
..
$ echo .[].[]
..
$ echo .[].xyz[]
..
$ echo .xyz[].xyz[]
.xyz[].xyz[]
$ echo .xyz[].[]
.xyz[].[]

Aparentemente, esto parece estar dando vueltas a algo, pero no entiendo cómo se produce el resultado. Según tengo entendido, []es una clase de personaje vacía. Sería intuitivo si

  • solo coincidía con la cadena vacía; en este caso, esperaría que bash se reproduzca en su totalidad ya que nada coincide en este directorio, pero también coincide con cosas como ..aliases(en el primer ejemplo),
  • o nada en absoluto; en este caso, también esperaría que bash reproduzca la cadena en total.

Esto es con GNU bash, versión 4.4.23 (1) -release.

Jonas Schäfer
fuente

Respuestas:

25

El [comienza un conjunto. Un conjunto es terminado por ]. Pero hay una manera de tener ]como parte del conjunto, y eso es especificar ]el primer carácter. Como un conjunto vacío no tiene ningún sentido, esto no es ambiguo.

Entonces, sus ejemplos son básicamente todos un punto seguido de un conjunto que contiene un punto, por lo tanto, coincide con dos puntos.

Los ejemplos posteriores no encuentran ningún archivo y, por lo tanto, se devuelven textualmente.

RalfFriedl
fuente
4

Solo las cadenas citadas no están sujetas a glob:

$ echo ".[].aliases[]"
.[].aliases[]

Pero las cadenas que no se citan están sujetas a un problema. La lista de archivos que coinciden modificará una cadena sin comillas que contiene una *o una ?o (válida) [](expresión de paréntesis). De la misma manera que a *se transformará en todos los archivos en el directorio correspondiente y a ?coincidirá con los archivos de un solo carácter, un (válido) []hará coincidir los archivos con los caracteres dentro de los corchetes. Un punto es un carácter válido:

$ echo a[.]b
a[.]b

$ touch "a.b"
$ echo a[.]b
a.b

Para poder hacer coincidir un ], debe ser el primer carácter dentro de los corchetes:

$ touch "a]b"
$ ls a[]]b
a]b

Una expresión de paréntesis vacía no tiene sentido (y no se expande):

$ touch ab
$ ls a[]b
ls: cannot access 'a[]b': No such file or directory

Por eso funciona esto:

$ touch a]c abc afc azc a:c a?c aoc 
$ ls a[]bfz:?]c
abc  a:c  a?c  a]c  afc  azc

Para [la idea es similar:

$ touch a[c
$ ls a[[]c
a[c

pero podría estar en cualquier posición en una expresión de paréntesis:

$ ls a[]bf[z:?]c
abc  a:c  a?c  a[c  a]c  afc  azc

$ ls a[]bfz:?[]c
abc  a:c  a?c  a[c  a]c  afc  azc

La cadena que ha publicado .[].foo[]coincidirá con un punto seguido de a ], a ., a f, a oo a [. Esto es similar a:

$ echo a[].foo[]c
a[c a]c afc aoc

Y coincidirá de la siguiente manera:

$ touch .] .f .o .[ .a .b .z

$ echo .[].foo[]
.. .[ .] .f .o

Tenga en cuenta que la entrada del directorio ..no necesita ser creada ya que existe dentro de cada directorio de manera predeterminada. Pero un punto simple .no coincidirá con un globo, ya que debe coincidir explícitamente (mediante el uso de un punto).

Pero eso no coincidirá, ..aliasesya que la expresión de paréntesis solo coincidirá con un carácter. Para hacer coincidir varios caracteres, debe usar un *(cualquier cosa):

$ touch ..a ..l ..i ..aliases ..alias ..ali
$ echo .[].aliases[]
.. .[ .] .a

$ echo .[].aliases[]*
.. .[ .] .a ..a ..ali ..alias ..aliases ..i ..l
Isaac
fuente