Qu’est-ce que le globbing et comment l’utiliser sous Linux ?
Le globaling est comme des expressions régulières pour vos noms de fichiers. Malheureusement, elle est souvent mal comprise, bien qu'il s'agisse d'une compétence essentielle en ligne de commande que tout le monde connaît au moins quelque chose. Transformez ces connaissances superficielles en une meilleure compréhension.
Sommaire
Qu’est-ce que la globalisation ?
« Globbing » est une version informelle du terme « extension de nom de fichier ». À l'aide de modèles spéciaux, vous pouvez identifier les noms de fichiers en fonction de modèles plutôt que de correspondances littérales exactes.
Le premier exemple de globbing que tout le monde rencontre se présente sous ce genre de format :
ls *.txt
Cela affiche une liste de fichiers dont les noms se terminent par l'extension « .txt » dans votre répertoire actuel. Dans cet exemple, le * correspond à n'importe quelle chaîne, y compris aucune, il correspondra donc aux fichiers portant ces noms :
-
à propos de.txt
-
un nom de fichier avec des espaces.txt
Cela ne correspondrait pas :
Fichiers cachés commençant par un . constituent un cas particulier. Pour faire correspondre les fichiers cachés, vous devez commencer votre modèle par un « ». personnage.
Il n'existe que deux autres types de correspondance dans le cas standard. Le ? le motif correspond à n’importe quel caractère : un exactement. Et le (…) le motif correspond à un seul caractère de l'ensemble inclus, qui peut également inclure des plages (comme az) et les classes de caractères (comme :chiffre:).
Avec seulement ces règles, vous pouvez créer des modèles assez sophistiqués pour correspondre à différents ensembles de fichiers, en fonction de vos besoins. Ainsi, par exemple, vous pourriez utiliser ls (amz)*(:chiffre:).?? Pour afficher tous les fichiers commençant par un a, un m ou un z et se terminant par un chiffre suivi d'un point et d'une extension d'exactement deux lettres.
Vous pouvez parfois voir un motif impliquant des accolades, comme ls*. {md, démarque}qui répertorie tous les fichiers se terminant par l'une ou l'autre extension. Techniquement, cette expansion d'accolade est distincte du processus de globalisation, mais il est courant d'utiliser les deux ensemble.
Comment fonctionne la globalisation ?
Le globaling est géré par votre shell, et non par la commande que vous exécutez. Considérez ce qui se passe lorsque vous courez ls *.txt. Vous pourriez penser que le programme ls reçoit « *.txt » comme argument, détermine les fichiers correspondant à ce modèle et imprime les résultats.
En fait, le shell est chargé de transformer « *.txt » en « foo.txt », « hello.txt », etc. Il transmet ensuite ces valeurs à la commande ls comme arguments. Ls n'a donc jamais à se soucier de la gestion de « *.txt » ; le shell le gère.
C'est la cause d'un problème courant avec des commandes telles que find :
find . -name *.txt
En exécutant cette commande, vous vous attendez à ce que find localise tous les fichiers texte du répertoire actuel et de tous ses sous-répertoires. Cependant, Bash fait ce qui suit :
-
Voit le « * » et convertit « *.txt » en une liste de noms de fichiers correspondants, qui proviendront tous du répertoire actuel uniquement.
-
Exécute la commande, par exemple, trouver . -name fichiera.txt fichierb.txt fichierc.txt.
Confirmez au préalable la commande que votre shell va réellement exécuter en la préfixant avec echo :
Le problème est maintenant que find se plaindra d'un « principal ou opérateur inconnu » ; et vous vous gratterez probablement la tête en essayant de comprendre ce que cela signifie !
L'option -name (find appelle cela un « primaire ») ne peut prendre qu'un seul argument lui-même, donc find est confus lorsqu'il voit « fileb.txt » et abandonne. La bonne façon d'exécuter cette commande est la suivante :
find . -name '*.txt'
Citer l'expression (avec des guillemets simples ou doubles) signifie que le shell n'effectuera pas d'expansion du nom de fichier, transmettant le modèle à find à la place.
Que peut faire d'autre la globalisation ?
Dans Bash, les caractères globaux principaux sont *, ? et (…). Cependant, Bash prend en charge un ensemble étendu de caractères génériques avec plus de fonctionnalités. Il s'agit principalement de prendre en charge les modèles répétés et de rapprocher le globbing de la correspondance complète des expressions régulières.
La globalisation étendue est généralement activée par défaut, mais si ce n'est pas le cas (par exemple, dans Bash 3.2 sur macOS), vous devrez le faire avec cette commande :
shopt -s extglob
Une fois activé, vous pourrez utiliser les éléments suivants :
-
?(liste de modèles) pour correspondre à 0 ou 1 occurrence des modèles donnés.
-
*(liste de modèles) pour faire correspondre 0 ou plusieurs occurrences des modèles donnés.
-
+(pattern-list) pour faire correspondre 1 ou plusieurs occurrences des modèles donnés.
-
@(pattern-list) pour correspondre à 1 des modèles donnés.
-
!(pattern-list) pour correspondre à tout sauf à l'un des modèles donnés.
Par exemple, vous pouvez faire correspondre les fichiers nommés « a », « aa » et « aaaaaa » avec le glob +(a). Vous pouvez faire correspondre les fichiers « README.md », « README.txt » et « README » avec le modèle LISEZMOI ? (.md|.txt).
Si vous êtes familier avec les expressions régulières, il est facile d'oublier que les globs sont implicitement ancrés. Cela signifie qu'un modèle comme +(a) ne correspondra qu'aux fichiers constitués uniquement du caractère « a », plutôt qu'à tout fichier contenant au moins un caractère « a » quelque part au milieu.
Étant donné que la globalisation est gérée par votre shell, la syntaxe qu'elle prend en charge peut varier, vous devez donc toujours consulter la documentation de votre shell. Le shell Zsh prend également en charge les bases, mais il offre une syntaxe étendue plus proche des expressions régulières. Par exemple, Zsh prend en charge le regroupement avec des parenthèses, ce qui ressemble à la syntaxe étendue de Bash :
ls (file1|file2) # ls file1 file2
De nombreux shells, notamment Bash et Zsh, ajoutent une fonctionnalité de globalisation récursive, dans laquelle vous pouvez développer les correspondances de fichiers de manière récursive. En utilisant cela, vous pouvez faire correspondre zéro ou plusieurs répertoires avec le modèle **. Donc ls **/*.txt trouvera tous les fichiers .txt dans le répertoire actuel ou dans l'un de ses sous-répertoires, à n'importe quelle profondeur :
Dans Bash, il s'agit d'un autre paramètre facultatif du shell, vous devrez donc l'activer :
shopt -s globstar
Cela vaut la peine de maîtriser la syntaxe de base conforme à POSIX pour la globalisation : ?, * et (…). Avec ces modèles, vous serez en mesure de gérer efficacement des groupes de fichiers, économisant ainsi de précieux efforts de frappe. Si vous êtes engagé dans un shell particulier, vous obtiendrez un petit bonus en apprenant sa syntaxe étendue.
