Comment analyser correctement les noms de fichiers dans Bash –
Les conventions de dénomination des fichiers Bash sont très riches et il est facile de créer un script ou une seule ligne qui analyse de manière incorrecte les noms de fichiers. Apprenez à analyser correctement les noms de fichiers et assurez-vous ainsi que vos scripts fonctionnent comme prévu!
Sommaire
Le problème de l’analyse correcte des noms de fichiers dans Bash
Si vous utilisez Bash depuis un certain temps et que vous avez écrit des scripts dans son riche langage Bash, vous aurez probablement rencontré des problèmes d’analyse de nom de fichier. Jetons un coup d’œil à un exemple simple de ce qui peut mal tourner:
touch 'a > b'
Ici, nous avons créé un fichier qui a un réel CR
(retour chariot) introduit en appuyant sur Entrée après le a
. Les conventions de dénomination des fichiers Bash sont très riches, et bien que cela soit cool à certains égards, nous pouvons utiliser des caractères spéciaux comme ceux-ci dans un nom de fichier, voyons comment ce fichier se comporte lorsque nous essayons de prendre des mesures dessus:
ls | xargs rm
Cela n’a pas fonctionné. xargs
prendra l’entrée de ls
(via le |
pipe), et passez-le à rm
, mais quelque chose a mal tourné dans le processus!
Ce qui ne va pas, c’est que la sortie de ls
est pris littéralement par xargs
, et le ‘enter’ (CR
– Retour chariot) dans le nom de fichier est vu par xargs
comme un caractère de terminaison réel, pas un CR
à transmettre rm
comme cela devrait être.
Illustrons cela d’une autre manière:
ls | xargs -I{} echo '{}|'
C’est clair: xargs
traite l’entrée en deux lignes individuelles, divisant le nom de fichier d’origine en deux! Même si nous devions résoudre les problèmes d’espace par une analyse sophistiquée à l’aide de sed, nous rencontrerions bientôt d’autres problèmes lorsque nous commencerons à utiliser d’autres caractères spéciaux tels que des espaces, des barres obliques inverses, des guillemets et plus encore!
touch 'a b' touch 'a b' touch 'ab' touch 'a"b' touch "a'b" ls
Même si vous êtes un développeur Bash chevronné, vous pouvez frissonner en voyant des noms de fichiers comme celui-ci, car il serait très complexe, pour la plupart des outils Bash courants, d’analyser correctement ces fichiers. Vous auriez à faire toutes sortes de modifications de chaîne pour que cela fonctionne. Autrement dit, à moins que vous n’ayez la recette secrète.
Avant de plonger dans cela, il y a encore une chose – un must-know – que vous pouvez rencontrer lors de l’analyse ls
production. Si vous utilisez un code couleur pour les listes de répertoires, qui est activé par défaut sur Ubuntu, il est facile d’exécuter dans un autre ensemble de ls
problèmes d’analyse.
Celles-ci ne sont pas vraiment liées à la façon dont les fichiers sont nommés, mais plutôt à la façon dont les fichiers sont présentés en sortie de ls
. le ls
la sortie contiendra des codes hexadécimaux qui représentent la couleur à utiliser sur votre terminal.
Pour éviter de les rencontrer, utilisez simplement --color=never
en option pour ls
:ls --color=never
.
Dans Mint 20 (un excellent système d’exploitation dérivé d’Ubuntu), ce problème semble résolu, bien que le problème puisse toujours être présent dans de nombreuses autres versions ou plus anciennes d’Ubuntu, etc. J’ai vu ce problème aussi récent que mi-août 2020 sur Ubuntu.
Même si vous n’utilisez pas de code couleur pour vos listes de répertoires, il est possible que votre script s’exécute sur d’autres systèmes que vous ne possédez pas ou ne gérez pas. Dans un tel cas, vous souhaiterez également utiliser cette option pour empêcher les utilisateurs d’une telle machine de s’exécuter dans le problème décrit.
Revenant à notre recette secrète, voyons comment nous pouvons nous assurer que nous n’aurons aucun problème avec les caractères spéciaux dans les noms de fichiers Bash. La solution fournie évite toute utilisation de ls
, ce que l’on ferait bien d’éviter en général, de sorte que les problèmes de codage couleur ne sont pas non plus applicables.
Il y a encore des moments où ls
l’analyse est rapide et pratique, mais elle sera toujours délicate et probablement «sale» dès que des caractères spéciaux sont introduits – sans parler de l’insécurité (les caractères spéciaux peuvent être utilisés pour introduire toutes sortes de problèmes).
La recette secrète: la résiliation NULL
Les développeurs d’outils Bash ont réalisé ce même problème plusieurs années plus tôt et nous ont fourni: NULL
Résiliation!
Quel est NULL
résiliation vous demandez-vous? Considérez comment dans les exemples ci-dessus, CR
(ou littéralement entrer) était le principal personnage de terminaison.
Nous avons également vu comment des caractères spéciaux comme les guillemets, les espaces blancs et les barres obliques inverses peuvent être utilisés dans les noms de fichiers, même s’ils ont des fonctions spéciales lorsqu’il s’agit d’autres outils d’analyse et de modification de texte Bash comme sed. Maintenant, comparez cela avec le -0
option pour xargs, de man xargs
:
-0, –null Les éléments d’entrée sont terminés par un caractère nul au lieu d’un espace blanc, et les guillemets et la barre oblique inverse ne sont pas spéciaux (chaque caractère est pris littéralement). Désactive la fin de la chaîne de fichier, qui est traitée comme tout autre argument. Utile lorsque les éléments d’entrée peuvent contenir des espaces, des guillemets ou des barres obliques inverses. L’option GNU find -print0 produit une entrée adaptée à ce mode.
Et le -print0
option pour find
, de man find
:
-fprint0 fichier Vrai; imprime le nom complet du fichier sur la sortie standard, suivi d’un caractère nul (au lieu du caractère de nouvelle ligne utilisé par -print). Cela permet aux noms de fichiers qui contiennent des retours à la ligne ou d’autres types d’espace blanc d’être correctement interprétés par les programmes qui traitent la sortie de recherche. Cette option correspond à l’option -0 de xargs.
le Vrai; ici signifie Si l’option est spécifiée, ce qui suit est vrai;. Les deux avertissements clairs donnés ailleurs dans la même page de manuel sont également intéressants:
- Si vous transférez la sortie de find dans un autre programme et qu’il y a la moindre possibilité que les fichiers que vous recherchez contiennent une nouvelle ligne, vous devriez sérieusement envisager d’utiliser l’option -print0 au lieu de -print. Consultez la section NOMS DE FICHIER INHABITUELS pour plus d’informations sur la manière dont les caractères inhabituels dans les noms de fichiers sont traités.
- Si vous utilisez find dans un script ou dans une situation où les fichiers correspondants peuvent avoir des noms arbitraires, vous devez envisager d’utiliser -print0 au lieu de -print.
Ces avertissements clairs nous rappellent que l’analyse des noms de fichiers dans bash peut être, et reste, une affaire délicate. Cependant, avec les bonnes options pour find
, à savoir -print0
, et xargs
, à savoir -0
, tous nos caractères spéciaux contenant des noms de fichiers peuvent être analysés correctement:
ls find . -name 'a*' -print0 find . -name 'a*' -print0 | xargs -0 ls find . -name 'a*' -print0 | xargs -0 rm
Nous vérifions d’abord notre liste d’annuaire. Tous nos noms de fichiers contenant des caractères spéciaux sont là. Nous faisons ensuite un simple find ... -print0
pour voir la sortie. Nous notons que les chaînes sont NULL
terminé (avec le NULL
ou