Extension de nom de file: search de correspondance de model d'utilitaire vs correspondance de model de shell Bash

Pour l'extension de nom de file, l'option '-name' de l'utilitaire 'find' semble fonctionner de la même manière, mais pas exactement la même chose que la correspondance de model embedded du shell bash.

Voici les sections pertinentes du manuel de reference GNU:

  • Correspondance de model de shell Bash: http://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching
  • 'find' correspondance de model d'utilité: http://www.gnu.org/software/findutils/manual/html_mono/find.html#Shell-Pattern-Matching

C'est très déroutant tout seul. Pour append à cette confusion, la section 2.1.4 de la page de manuel de l'utilitaire 'find' (référencée ci-dessus) s'intitule «Shell Pattern Matching», ce qui implique que «find» utilise la fonctionnalité de correspondance du model embedded au shell. Cependant, cela ne semble pas être le cas car selon la page de manuel 'find' ( http://goo.gl/ngQTKx ), sous '-name pattern', il est dit:

"La correspondance de nom de file est effectuée avec l'utilisation de la fonction de bibliothèque fnmatch (3). N'oubliez pas de placer le motif entre guillemets pour le protéger de l'expansion par le shell.

À partir de cela, il semble que ce n'est pas le shell qui effectue la search de motifs, mais l'utilitaire de search utilisant la bibliothèque fnmatch.

Voici mes questions:

  1. Est-ce que l'extension du nom de file par défaut du shell bash et la correspondance des templates (option du shell extglob désactivée) sont différentes de celles de l'utilitaire find en utilisant l'option -name?
  2. Si oui, quelles sont ces différences?
  3. Est-ce que bash utilise aussi la bibliothèque fnmatch ou un autre mécanisme pour l'extension de nom de file et la correspondance de model?

Dans le shell, vous devez distinguer la génération / expansion de nom de file (aka globbing ): un model qui s'étend à une list de files à partir de la correspondance de templates . globbing utilise la correspondance de motifs en interne , mais c'est avant tout un opérateur de générer une list de files en fonction d'un model .

*/*.txt est un model qui correspond à une séquence de 0 caractères ou plus suivi de / suivi d'une séquence de zéro ou plusieurs caractères suivis de .txt . Lorsqu'il est utilisé comme un model de shell comme dans:

 case $file in */*.txt) echo match esac 

Il correspondra au file=.foo/bar/baz.txt .

Cependant */*.txt comme un glob est quelque chose de connexe mais plus complexe.

En développant */*.txt dans une list de files, le shell ouvrira le directory courant, listra son contenu, finda les files non-cachés de type directory (ou lien symbolique au directory) qui correspondent à * , sortingent cette list, de ceux-ci, listr leur contenu et find les non-masqués qui correspondent *.txt .

Il ne développera jamais .foo/bar/bar.txt même si cela correspond au model parce que ce n'est pas ainsi que cela fonctionne. D'autre part, les paths de file générés par un glob correspondront tous à ce model.

De même, un glob comme foo[a/b]baz* finda tout le file dont le nom commence par b]baz dans le foo[a directory.

Donc, nous avons déjà vu que pour le globbing, mais pas pour la correspondance de motifs, / est spécial (globs sont en quelque sorte séparés sur / et chaque partie traitée séparément) et les files point sont traités spécialement.

La mise à l'échelle des shells et la correspondance des motifs font partie de la syntaxe du shell. Il est entrelacé avec la citation et d'autres forms d'expansion.

 $ bash -c 'case "]" in [x"]"]) echo true; esac' true 

Citant que ] supprime sa signification spéciale (de fermer le précédent [ ):

Il peut même assez confus quand vous mélangez tout:

 $ ls * \* \ax $ p='\*' ksh -xc 'ls $p' + ls '\*' '\a' \* \a 

OK \* est tous les files commençant par \ .

 $ p='\*' bash -xc 'ls $p' + ls '\*' \* 

Ce ne sont pas tous les files commençant par \ . Donc, d'une manière ou d'une autre, \ doit avoir échappé au * , mais encore une fois il ne correspond pas * soit …

Pour find, c'est beaucoup plus simple. find descend l'arborescence de directorys à chaque argument de file qu'il reçoit, puis effectue les tests comme indiqué pour chaque file rencontré.

Pour -type f , c'est vrai si le file est un file normal, false sinon -name <some-pattern> , c'est vrai si le nom du file considéré correspond au pattern, false sinon. Il n'y a pas de concept de file caché ou / handling ou de guillemets ici, c'est juste une string (le nom du file) correspondant à un pattern.

Par exemple, -name '*foo[a/b]ar' (qui passe -name et *foo[a/b]ar arguments à find ) correspondra à foobar et .fooaar . Il ne correspondra jamais à foo/bar , mais c'est parce que -name correspond au nom du file, ce serait avec -path place.

Maintenant, il existe une forme de citation / échappement – pour la find – reconnue ici, et c'est seulement avec une barre oblique inverse. Cela permet d'échapper aux opérateurs. Pour le shell, c'est fait dans le cadre de la citation de shell habituelle ( \ est l'un des mécanismes de citation du shell). Pour find ( fnmatch() ), cela fait partie de la syntaxe du model.

Par exemple, le nom -name '\**' correspondra aux files dont le nom commence par * . -name '*[\^x]*' correspondrait aux files dont le nom contient ^ ou x

Or, quant aux différents opérateurs reconnus par find , fnmatch() , bash et divers autres shells, ils devraient tous être d'accord au less sur un sous-set commun: * fnmatch() et [...] .

La mise en œuvre d'un shell particulier ou d' find implémentation find utilise la fonction fnmatch() système ou la leur. GNU find fait au less sur les systèmes GNU. Les coquilles sont très peu susceptibles de les utiliser car cela compliquerait la chose pour eux et ne valait pas l'effort.

bash certainement pas. Les shells de Moddern comme ksh, bash, zsh ont aussi des extensions sur * ,? , [...] et un certain nombre d'options et de parameters spéciaux ( GLOBIGNORE / FIGNORE ) pour affecter leur comportement de globulation.

Notez également que, à côté de fnmatch() qui implémente la correspondance du model de shell, il y a aussi la fonction glob() qui implémente quelque chose de similaire au shell shell.

Maintenant, ils peuvent être des différences subtiles entre les opérateurs de correspondance de motifs dans ces différentes implémentations.

Par exemple, pour GNU fnmatch() , * ou [!x] ne correspondent pas à un octet ou à une séquence d'octets qui ne forment pas de caractères valides alors que bash (et la plupart des autres shells) le feraient. Par exemple, sur un système GNU find . -name '*' find . -name '*' peut ne pas correspondre aux files dont le nom contient des caractères invalides, alors que bash -c 'echo *' les listra (tant qu'ils ne commencent pas par . ).

Nous avons déjà mentionné la confusion qui peut être encourue en citant.