No shell, você precisa distinguir geração / expansão de nome de arquivo ( globbing ): um padrão que se expande para uma lista de arquivos do padrão de correspondência . globbing usa padrão de correspondência internamente , mas é realmente antes de tudo um operador para gerar uma lista de arquivos baseados em um padrão .
*/*.txt é um padrão que corresponde a uma sequência de 0 ou mais caracteres seguida por / seguido por uma sequência de zero ou mais caracteres seguida por .txt . Quando usado como um padrão de shell como em:
case $file in
*/*.txt) echo match
esac
Ele corresponderá a file=.foo/bar/baz.txt .
No entanto, */*.txt como glob é algo relacionado, mas mais complexo.
Ao expandir */*.txt em uma lista de arquivos, o shell abrirá o diretório atual, listará seu conteúdo, localizará os arquivos não ocultos do diretório type (ou symlink to directory) que correspondem a * , classifiquem essa lista , abra cada um deles, liste seu conteúdo e encontre os não ocultos que correspondem a *.txt .
Ele nunca expandirá .foo/bar/bar.txt , mesmo que isso corresponda ao padrão, porque não é assim que funciona. Por outro lado, os caminhos de arquivos gerados por um glob corresponderão a esse padrão.
Da mesma forma, um glob como foo[a/b]baz* encontrará todo o arquivo cujo nome começa com b]baz no diretório foo[a .
Então, já vimos que para globbing, mas não para correspondência de padrões, / é especial (globs são de alguma forma divididos em / e cada parte tratada separadamente) e dot-files são tratados especialmente.
Shell globbing e correspondência de padrões fazem parte da sintaxe do shell. Está entrelaçado com citações e outras formas de expansão.
$ bash -c 'case "]" in [x"]"]) echo true; esac'
true
Citando que ] remove seu significado especial (de fechar o% anterior[):
Pode até ficar bastante confuso quando você mistura tudo:
$ ls
* \* \a x
$ p='\*' ksh -xc 'ls $p'
+ ls '\*' '\a'
\* \a
OK \* é todos os arquivos que começam com \ .
$ p='\*' bash -xc 'ls $p'
+ ls '\*'
\*
Não são todos os arquivos que começam com \ . Então, de alguma forma, \ deve ter escapado do * , mas, novamente, não é igual a * ...
Para encontrar, é muito mais simples. find desce a árvore de diretórios em cada um dos argumentos de arquivo que recebe e então faz os testes conforme instruído para cada arquivo encontrado.
Para -type f , isso é verdadeiro se o arquivo for um arquivo normal, falso caso contrário, para -name <some-pattern> , se o nome do arquivo atualmente considerado corresponde ao padrão, false caso contrário. Não há nenhum conceito de arquivo oculto ou / handling ou shell quoting aqui, isso é apenas a correspondência de uma string (o nome do arquivo) contra um padrão.
Portanto, por exemplo, -name '*foo[a/b]ar' (que passa -name e *foo[a/b]ar argumentos para find ) corresponderá a foobar e .fooaar . Ele nunca corresponderá a foo/bar , mas isso porque -name corresponde ao nome do arquivo, seria com -path .
Agora, há uma forma de citar / escapar - para find - reconhecida aqui, e isso é apenas com a barra invertida. Isso permite escapar de operadores. Para o shell, ele é feito como parte da cotação usual do shell ( \ é um dos mecanismos de cotação do shell). Para find ( fnmatch() ), isso faz parte da sintaxe do padrão.
Por exemplo, -name '\**' corresponderia aos arquivos cujo nome começa com * . -name '*[\^x]*' corresponderia em arquivos cujo nome contenha ^ ou x ...
Agora, para os diferentes operadores reconhecidos por find , fnmatch() , bash e vários outros shells, todos devem concordar, pelo menos, com um subconjunto comum: * , ? e [...] .
Se um determinado shell ou find de implementação usa a função fnmatch() do sistema ou a sua própria depende da implementação. O GNU find faz pelo menos nos sistemas GNU. É muito improvável que os shells os usem, já que isso seria complicado para eles e não vale o esforço.
bash certamente não. Shells modulares como ksh, bash, zsh também têm extensões sobre * , ? , [...] e um número de opções e parâmetros especiais ( GLOBIGNORE / FIGNORE ) para afetar seu comportamento de globulação.
Além disso, observe que, além de fnmatch() , que implementa a correspondência de padrões de shell, há também as glob()
Agora, podem haver diferenças sutis entre os operadores de correspondência de padrões nessas várias implementações.
Por exemplo, para% GNUfnmatch(), ? , * ou [!x] não corresponderia a um byte ou sequência de bytes que não formam caracteres válidos enquanto bash (e a maioria dos outros shells) seria. Por exemplo, em um sistema GNU, find . -name '*' pode não corresponder a arquivos cujo nome contém caracteres inválidos, enquanto bash -c 'echo *' os listará (desde que não iniciem com . ).
Já mencionamos a confusão que pode ser incorrida citando.