En el shell, debe distinguir la generación / expansión de nombre de archivo (también conocido como globbing : un patrón que se expande a una lista de archivos) de la coincidencia de patrones . globbing utiliza la coincidencia de patrones internamente , pero en realidad es ante todo un operador generar una lista de archivos basada en un patrón .
*/*.txt
es un patrón que coincide con una secuencia de 0 o más caracteres, seguido de /
, seguido de una secuencia de cero o más caracteres, seguido de .txt
. Cuando se usa como un patrón de shell como en:
case $file in
*/*.txt) echo match
esac
Coincidirá con file=.foo/bar/baz.txt
.
Sin embargo, */*.txt
como glob es algo relacionado pero más complejo.
Al expandirse */*.txt
a una lista de archivos, el shell abrirá el directorio actual, enumerará su contenido, encontrará los archivos no ocultos de tipo directorio (o enlace simbólico al directorio) que coincidan *
, clasifique esa lista, abra cada uno de ellos, enumere su contenido , y encuentre los que no están ocultos que coinciden *.txt
.
Nunca se expandirá .foo/bar/bar.txt
aunque coincida con el patrón porque no es así como funciona. Por otro lado, todas las rutas de archivos generadas por un glob coincidirán con ese patrón.
Del mismo modo, un glob like foo[a/b]baz*
encontrará todos los archivos cuyo nombre comienza b]baz
en el foo[a
directorio.
Por lo tanto, ya lo hemos visto para el engorde, pero no para la coincidencia de patrones, /
es especial (los globos se dividen de alguna manera /
y cada parte se trata por separado) y los archivos de puntos se tratan especialmente.
El globbing de shell y la coincidencia de patrones son parte de la sintaxis de shell Está entrelazado con citas y otras formas de expansión.
$ bash -c 'case "]" in [x"]"]) echo true; esac'
true
Cita que ]
elimina su significado especial (de cerrar el anterior [
):
Puede ser aún más confuso cuando mezclas todo:
$ ls
* \* \a x
$ p='\*' ksh -xc 'ls $p'
+ ls '\*' '\a'
\* \a
OK \*
son todos los archivos que comienzan con \
.
$ p='\*' bash -xc 'ls $p'
+ ls '\*'
\*
No todos los archivos comienzan con \
. Entonces, de alguna manera, \
debe haber escapado del *
, pero, de nuevo, tampoco coincide *
...
Para encontrar, es mucho más simple. find
desciende el árbol de directorios en cada uno de los argumentos de archivo que recibe y luego realiza las pruebas como se indica para cada archivo encontrado.
Para -type f
, eso es cierto si el archivo es un archivo normal, falso de lo contrario para -name <some-pattern>
, eso es cierto si el nombre del archivo actualmente considerado coincide con el patrón, falso de lo contrario. No hay ningún concepto de archivo oculto o /
manejo o citación de shell aquí, eso solo coincide con una cadena (el nombre del archivo) contra un patrón.
Entonces, por ejemplo, -name '*foo[a/b]ar'
(que pasa -name
y *foo[a/b]ar
argumentos a find
) coincidirá foobar
y .fooaar
. Nunca coincidirá foo/bar
, pero eso se debe a que -name
coincide con el nombre del archivo; lo haría con en su -path
lugar.
Ahora, hay una forma de citar / escapar - parafind
- reconocida aquí, y eso es solo con barra invertida. Eso permite escapar de los operadores. Para el shell, se realiza como parte de las citas habituales de shell ( \
es uno de los mecanismos de cotización del shell). Para find
( fnmatch()
), eso es parte de la sintaxis del patrón.
Por ejemplo, -name '\**'
coincidiría en archivos cuyo nombre comience con *
. -name '*[\^x]*'
coincidiría en archivos cuyo nombre contiene ^
o x
...
Ahora, en cuanto a los diferentes operadores reconocidos por find
, fnmatch()
, bash
y varios otros proyectiles, todos ellos deben estar de acuerdo al menos en un subconjunto común: *
, ?
y [...]
.
Si un shell o find
implementación particular utiliza la fnmatch()
función del sistema o la suya depende de la implementación. GNU lo find
hace al menos en sistemas GNU. Es muy poco probable que los proyectiles los usen, ya que les complicaría las cosas y no valdría la pena el esfuerzo.
bash
Ciertamente no lo hace. Conchas modernas, como ksh, bash, zsh también tienen extensiones sobre *
, ?
, [...]
y una serie de opciones y parámetros especiales ( GLOBIGNORE
/ FIGNORE
) que afectan a su comportamiento comodines.
También tenga en cuenta que además de lo fnmatch()
que implementa la coincidencia de patrones de shell, también existe la glob()
función que implementa algo similar al globbing de shell.
Ahora, puede haber diferencias sutiles entre los operadores de coincidencia de patrones en esas diversas implementaciones.
Por ejemplo, para GNU fnmatch()
, ?
, *
o [!x]
que no coincide con un byte o una secuencia de bytes que no forman caracteres válidos, mientras que bash
(y otros intérpretes de comandos) haría. Por ejemplo, en un sistema GNU, es find . -name '*'
posible que no coincidan los archivos cuyo nombre contiene caracteres no válidos, mientras bash -c 'echo *'
que los enumerará (siempre que no comiencen con .
).
Ya hemos mencionado la confusión en la que se puede incurrir al citar.