Je souhaite supprimer les espaces de fin de tous les fichiers d'une hiérarchie de répertoires récursifs. J'utilise ceci:
find * -type f -exec sed 's/[ \t]*$//' -i {} \;
Cela fonctionne, mais supprimera également les "espaces blancs" de fin des fichiers binaires trouvés, ce qui n'est pas souhaitable.
Comment dire find
pour éviter d'exécuter cette commande sur des fichiers binaires?
file
qui peuvent inspecter les données.Réponses:
Vous pouvez essayer d'utiliser la
file
commande Unix pour aider à identifier les fichiers que vous ne voulez pas, mais je pense que ce serait mieux si vous spécifiez explicitement quels fichiers vous voulez frapper plutôt que ceux que vous ne voulez pas.pour éviter de traverser dans les fichiers de contrôle de source, vous voudrez peut-être quelque chose comme
Vous pouvez ou non avoir besoin de certaines barres obliques inverses en fonction de votre shell.
la source
-i
option pour sed . Il est difficile d'écrire une commande shell portable, n'est-ce pas?Cela peut être fait sur la ligne de commande.
la source
La réponse la plus simple et la plus portable consiste à exécuter ceci:
J'explique pourquoi ci-dessous, où je montre également comment le faire en utilisant uniquement la ligne de commande, ainsi que la façon de traiter les fichiers texte trans-ASCII comme ISO-8859-1 (Latin-1) et UTF-8, qui ont souvent non -ASCII espace blanc en eux.
Le reste de l'histoire
Le problème est que find (1) ne prend pas en charge l'
-T
opérateur filetest, ni ne reconnaît les encodages si c'est le cas - ce dont vous avez absolument besoin pour détecter UTF-8, l'encodage Unicode standard de facto.Ce que vous pourriez faire, c'est d'exécuter la liste des noms de fichiers à travers une couche qui jette des fichiers binaires. Par exemple
Cependant, vous avez maintenant des problèmes avec les espaces dans vos noms de fichiers, vous devez donc retarder cela avec une terminaison nulle:
Une autre chose que vous pourriez faire est de ne pas l'utiliser
find
maisfind2perl
, puisque Perl comprend-T
déjà:Et si vous voulez que Perl suppose que ses fichiers sont en UTF-8, utilisez
Ou vous pouvez enregistrer le script résultant dans un fichier et le modifier. Vous ne devriez pas vraiment exécuter le
-T
filetest sur n'importe quel ancien fichier, mais plutôt uniquement sur ceux qui sont des fichiers simples comme déterminé par-f
. Sinon, vous risquez d'ouvrir des offres spéciales sur les appareils, de bloquer sur fifos, etc.Cependant, si vous allez faire tout cela, vous pourriez tout aussi bien ignorer sed (1). D'une part, il est plus portable, car la version POSIX de sed (1) ne comprend pas
-i
, contrairement à toutes les versions de Perl. Les dernières versions de sed se sont approprié avec amour l'-i
option très utile de Perl où ti apparaît pour la première fois.Cela vous donne également la possibilité de corriger votre regex, aussi. Vous devez vraiment utiliser un modèle qui correspond à un ou plusieurs espaces horizontaux de fin, et pas seulement à zéro, sinon vous exécuterez plus lentement en cas de copie inutile. C'est ça:
devrait être
Cependant, comment comprendre sed (1) qui nécessite une extension non POSIX, généralement soit
-R
pour les Unités System System comme Solaris ou Linux, soit-E
pour celles BSD comme OpenBSD ou MacOS. Je soupçonne que c'est impossible sous AIX. Il est hélas plus facile d'écrire un shell portable qu'un script shell portable, vous savez.Avertissement sur 0xA0
Bien que ce soient les seuls caractères d'espace blanc horizontaux en ASCII, ISO-8859-1 et par conséquent également Unicode ont le NO-BREAK SPACE au point de code U + 00A0. C'est l'un des deux premiers caractères non ASCII trouvés dans de nombreux corpus Unicode, et j'ai récemment vu beaucoup de codes regex casser car ils l'ont oublié.
Alors, pourquoi ne faites-vous pas cela:
Si vous pouvez avoir des fichiers UTF-8 à traiter, ajouter
-CSD
, et si vous utilisez Perl v5.10 ou plus, vous pouvez utiliser\h
pour un espace horizontal et\R
un saut de ligne générique, qui comprend\r
,\n
,\r\n
,\f
,\cK
,\x{2028}
et\x{2029}
:Cela fonctionnera sur tous les fichiers UTF-8, quels que soient leurs sauts de ligne, en supprimant les espaces horizontaux de fin (propriété de caractère Unicode
HorizSpace
), y compris l'ESPACE NO-BREAK ESPACE qui se produit avant un saut de ligne Unicode (y compris les combos CRLF) à la fin de chaque ligne.Elle est également beaucoup plus portable que la version sed (1), car il n'y a qu'une seule implémentation perl (1), mais beaucoup de sed (1).
Le principal problème que je vois y rester est avec find (1), car sur certains systèmes vraiment récalcitrants (vous savez qui vous êtes, AIX et Solaris), il ne comprendra pas la
-print0
directive supercritique . Si tel est votre cas, vous devez simplement utiliserFile::Find
directement le module de Perl et n'utiliser aucun autre utilitaire Unix. Voici une version pure Perl de votre code qui ne repose sur rien d'autre:Si vous utilisez uniquement des fichiers texte ASCII ou ISO-8859-1, c'est bien, mais si vous utilisez des fichiers ASCII ou UTF-8, ajoutez-les
-CSD
aux commutateurs de l'appel intérieur de Perl.Si vous avez des encodages mixtes des trois ASCII, ISO-8859-1 et UTF-8, je crains que vous ayez un autre problème. :( Vous devrez comprendre l'encodage fichier par fichier, et il n'y a jamais de bon moyen de le deviner.
Espace Unicode
Pour mémoire, Unicode possède 26 espaces différents. Vous pouvez utiliser l' utilitaire unichars pour les détecter. Seuls les trois premiers caractères blancs horizontaux sont presque jamais vus:
la source
GNU grep est assez bon pour identifier si un fichier est binaire ou non. À part Solaris, je suis sûr qu'il existe d'autres plates-formes qui ne sont pas fournies avec GNU grep installé par défaut, mais comme Solaris, je suis sûr que vous pouvez l'installer.
Si vous êtes dans Solaris, vous devez le remplacer
grep
par/opt/csw/bin/ggrep
.Les
grep
indicateurs font ce qui suit:l
ne répertorie que les noms de fichiers pour les fichiers correspondants,R
est récursif,I
correspond uniquement aux fichiers texte (ignore les fichiers binaires) etP
est pour la syntaxe des expressions régulières compatible Perl.La partie perl modifie le fichier sur place, supprimant tous les espaces / tabulations de fin.
Enfin: si UTF8 est un problème, la réponse de tchrist couplée à la mienne devrait être suffisante, à condition que la version que
grep
vous avez soit construite avec le support UTF8 (cependant, les responsables de paquets essaient généralement de fournir ce type de fonctionnalité).la source