Linux Fu: Globs Vs Regexp

Une fois, j’ai demandé à un développeur de logiciels au travail combien de fois nous avons appelé fork() dans notre code. J’admets que c’était un très gros projet, mais je m’attendais à ce que la réponse soit — au plus — à deux chiffres. Le développeur est revenu et a lu un certain nombre sur un morceau de papier qui se comptait par millions. Je leur ai dit qu’il n’y avait aucun moyen que nous ayons des millions d’appels à fork() et, bien sûr, nous ne l’avons pas fait. Le problème était que le développeur n’était pas clair sur la différence entre une expression régulière et un glob.

Des outils tels que grep utilisent des expressions régulières pour créer des modèles de recherche. je pourrais écrire [Hh]ack ?a ?[Dd]ay en tant qu’expression régulière pour faire correspondre des choses comme « HackaDay » et « Hack a day » et, même, « Hackaday » en utilisant un outil comme grep, awk ou de nombreux langages de programmation.

Alors, qu’est-ce qu’un globe ?

Le problème est que le shell utilise également la correspondance de modèles et utilise bon nombre des mêmes caractères que les expressions régulières. L’appel de fourche? Le modèle utilisé par le développeur était fork*. Ce serait OK – peut-être pas génial – en tant que glob si vous aviez peur qu’il y ait des appels qui commencent par fork mais avait ensuite quelque chose d’autre à la suite (comme un exec appel qui pourrait être execl, execv, ou l’un de plusieurs autres).

Si le shell voyait ce motif, il chercherait tout ce qui a commencé par fork puis il y avait zéro ou plusieurs caractères à sa suite. Mais en tant qu’expression régulière, le sens est tout à fait différent. Le motif signifiait en fait : les lettres f o r suivi de zéro ou plusieurs occurrences de la lettre k. Donc for correspondrait. Ainsi serait fork. Comme le ferait forkkkkk. Aussi des choses comme forth, format, et formula. Le nombre correspondant était donc énorme.

Guide de survie Glob

Globbing est généralement une fonction de la coquille. Lorsque vous entrez quelque chose comme :

ls a*

Le programme ls ne voit jamais le a*. Au lieu de cela, il voit la liste étendue des fichiers du shell commençant par la lettre a. Eh bien, ce n’est pas tout à fait vrai. S’il n’y a pas de fichiers qui correspondent au modèle glob, alors ls verra le texte que vous avez entré et imprimera probablement un message d’erreur qu’il ne peut pas trouver a*. Au moins, c’est le comportement par défaut. Vous pouvez modifier ce que fait le shell s’il ne trouve pas de correspondance (recherche nullglob et failglob).

C’est une bonne chose car cela signifie que les programmes n’ont pas à écrire leur propre globbing et que tout fonctionne de la même manière dans un seul shell. Il peut y avoir des différences, bien sûr, selon le shell que vous utilisez. Vous pouvez également désactiver le globbing dans certains shells. Dans bash, vous pouvez émettre :

set -f

Cependant, vous trouverez probablement cela frustrant, alors annulez-le avec :

set +f

Les caractères spéciaux les plus courants pour les globs sont :

  • * – zéro ou plusieurs caractères
  • ? – N’importe quel caractère
  • [] – Une classe de personnages comme [abc] ou [0-9]
  • [^] – Classe de caractères négative
  • [!] – Pareil que [^]

Si vous avez des noms de fichiers qui ont un an comme post07-26-2020.txt, vous pouvez écrire les globs suivants :

  • post*2020.txt – Tous les messages de 2020
  • post*202?.txt Tous les messages de 2020-2029 (ou, même, 202Z ; n’importe quel caractère correspondra)
  • poste0[345]*2020.txt – Tous les messages de mars, avril et mai 2020
  • Publier[!0][01]*.2021.txt – Publications d’octobre ou novembre 2021

Vous pouvez faire beaucoup avec un glob, mais vous ne pouvez pas vraiment tout faire. Bash a d’autres options d’extension qui peuvent aider, mais ce ne sont pas techniquement des globs. Par exemple, vous pouvez saisir :

process post{01,02,03,11,12}-*2020.txt

Cependant, cela s’étendra, que les fichiers existent ou non, pour :

post01-*2020.txt post02-*2020.txt post03-*2020.txt post11-*2020.txt post12-*2020.txt

Ensuite, le shell regroupera ces modèles pour les noms de fichiers réels. Vous pouvez en apprendre beaucoup plus sur la page de manuel bash. Recherche de correspondance de modèle.

Capture d'écran de man bash
La page de manuel bash a beaucoup sur la correspondance de modèles

Une petite syntaxe Regex

Les expressions régulières sont beaucoup plus expressives, mais aussi plus variables. Chaque programme qui propose des expressions régulières utilise son propre code et, dans certains cas, il est très différent des autres programmes. La bonne nouvelle est que la majorité des expressions régulières que vous souhaitez utiliser ne seront pas différentes. Habituellement, ce ne sont que les fonctionnalités les plus obscures qui changent, bien que ce soit peu de confort si vous appuyez sur l’une de ces fonctionnalités.

La syntaxe de base est probablement mieux représentée par grep. Cependant, si vous utilisez autre chose, vous devrez vérifier sa documentation pour voir en quoi ses expressions régulières peuvent être différentes.

Le plus gros problème est que le * et ? les caractères ont des significations complètement différentes de leurs homologues glob. Les * signifie zéro ou plus du modèle précédent. Donc 10* correspondra 1, 10, 100, 1000 etc.

Diagramme d'expressions régulières
Notre sujet regexp représenté graphiquement grâce à Regexper

Le point d’interrogation signifie que le modèle précédent est facultatif. Donc, 10?5 correspondra 105 et 15 aussi bien. Pour n’importe quel caractère, dans une expression régulière, vous utilisez un point. Donc, revenant à mon exemple initial, [Hh]ack ?a ?[Dd]ay vous pouvez voir comment cela n’a pas de sens en tant que glob. Le site Web Regexpr fait un bon travail d’interprétation graphique des expressions régulières, comme vous pouvez le voir.

Encore plus de confusion

Pour rendre les choses encore plus étranges, à partir de la version 3, bash propose des expressions régulières dans les scripts afin que vous puissiez avoir un script avec à la fois des globs et des expressions régulières qui vont tous les deux être bash.

Ensuite, il y a le fait que bash propose un style de glob différent avec lequel vous pouvez activer shopt -s extglob. Celles-ci sont en fait plus proches des expressions régulières, bien que la syntaxe soit un peu inversée.

Apprendre les expressions régulières

J’avais pensé vous offrir une aide-mémoire d’expressions régulières courantes, mais j’ai réalisé que je ne pouvais pas faire mieux que Dave Child, alors j’ai décidé de vous indiquer cela.

Les expressions régulières ont la réputation d’être difficiles, et cette réputation n’est pas totalement imméritée. Mais nous avons cherché des moyens de rendre les expressions régulières plus lisibles, et si vous avez besoin de pratique, essayez les mots croisés.