Comment supprimer les espaces blancs de fin de tous les fichiers de manière récursive?

122

Comment pouvez-vous supprimer tous les espaces blancs de fin d'un projet entier? En commençant par un répertoire racine et en supprimant l'espace blanc de fin de tous les fichiers de tous les dossiers.

De plus, je veux pouvoir modifier le fichier directement, et pas seulement tout imprimer sur stdout.

iamjwc
la source
Oh, cherchez-vous une solution "portable", ou une solution plus spécifique au système d'exploitation? Quel système d'exploitation utilisez-vous?
Joe Pineda le
3
J'aimerais voir une version de ceci qui fonctionnerait sur OS X Snow Leopard, et ignorerait les dossiers .git et .svn.
Trevor Turk

Réponses:

83

Voici une solution OS X> = 10.6 Snow Leopard.

Il ignore les dossiers .git et .svn et leur contenu. De plus, il ne laissera pas de fichier de sauvegarde.

export LC_CTYPE=C
export LANG=C
find . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 sed -i '' -E "s/[[:space:]]*$//"
puits profond
la source
10
Vous pouvez le rendre plus rapide en utilisant \+au lieu de *dans la chaîne de remplacement - Sinon, il correspond à chaque ligne.
l0b0
10
Vous pouvez utiliser [[: blank:]] pour supprimer les tabulations et les espaces.
Leif Gruenwoldt
21
Dans Mountain Lion, cela revient sed: RE error: illegal byte sequencepour moi.
Bryson
12
Pour ceux d'entre vous qui ont des problèmes avec la "séquence d'octets illégale": Entrez export LANG=Cet réessayez
Georg Ledermann
3
Dans OS X 10.9, j'avais également besoin de ce export LC_CTYPE=C que l'on trouve ici: stackoverflow.com/questions/19242275/…
kissgyorgy
31

Utilisation:

find . -type f -print0 | xargs -0 perl -pi.bak -e 's/ +$//'

si vous ne voulez pas que les fichiers ".bak" soient générés:

find . -type f -print0 | xargs -0 perl -pi -e 's/ +$//'

en tant qu'utilisateur zsh, vous pouvez omettre l'appel à rechercher et utiliser à la place:

perl -pi -e 's/ +$//' **/*

Remarque: Pour éviter la destruction de .gitrépertoire, essayez d' ajouter: -not -iwholename '*.git*'.

Seconde
la source
37
N'essayez pas cela dans un dépôt git, car cela peut corrompre le stockage interne de git.
mgold le
11
@mgold Too late, grrr; /
kenorb
3
Pour clarifier, il est normal de l'exécuter dans un sous-dossier d'un dépôt git, mais pas dans un dossier contenant un ou plusieurs repo git en tant que descendant, c'est-à-dire pas dans un dossier contenant des .gitrépertoires, quelle que soit la profondeur de leur imbrication.
Illya Moskvin
Combiner cette réponse avec @ deepwell's pour éviter les problèmes git / svnfind . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 perl -pi -e 's/ +$//'
William Denniss
1
Il y a probablement un meilleur moyen, mais j'ai récupéré après avoir modifié un dépôt git avec cela en clonant le dépôt dans un dossier séparé, puis en faisant, rsync -rv --exclude=.git repo/ repo2/après quoi les modifications locales dans repoétaient également dans le (non endommagé) repo2.
MatrixManAtYrService
29

Deux approches alternatives qui fonctionnent également avec les nouvelles lignes DOS (CR / LF) et font un très bon travail pour éviter les fichiers binaires :

Solution générique qui vérifie que le type MIME commence par text/:

while IFS= read -r -d '' -u 9
do
    if [[ "$(file -bs --mime-type -- "$REPLY")" = text/* ]]
    then
        sed -i 's/[ \t]\+\(\r\?\)$/\1/' -- "$REPLY"
    else
        echo "Skipping $REPLY" >&2
    fi
done 9< <(find . -type f -print0)

Solution spécifique au référentiel Git de Mat qui utilise l'-Ioption degit greppour ignorer les fichiers que Git considère comme binaires:

git grep -I --name-only -z -e '' | xargs -0 sed -i 's/[ \t]\+\(\r\?\)$/\1/'
l0b0
la source
3
Donc j'aime vraiment cette solution git. Cela devrait vraiment être au top. Je ne veux pas enregistrer les retours chariot. Mais je préfère celui-ci à celui que j'ai combiné en 2010.
odinho - Velmont
Mon git se plaint que l'expression -e est vide, mais cela fonctionne très bien en utilisant -e '. *'
muirbot
@okor Dans GNU, sedl'option suffixe to -iest facultative , mais dans BSDsed ce n'est pas le cas. Ce n'est de toute façon pas nécessaire à proprement parler ici, alors je vais simplement le supprimer.
l0b0
24

Dans Bash:

find dir -type f -exec sed -i 's/ *$//' '{}' ';'

Remarque: Si vous utilisez .gitréférentiel, essayez d' ajouter: -not -iwholename '.git'.

Adam Rosenfield
la source
Cela génère des erreurs comme celle-ci pour chaque fichier trouvé. sed: 1: "dir / file.txt": la commande a attend \ suivie de texte
iamjwc
Remplacement de ";" avec \; devrait marcher. (De plus, les citations autour de {} ne sont pas strictement nécessaires).
agnul le
4
Pour supprimer tous les espaces et pas seulement les espaces, vous devez remplacer le caractère d'espace par [: space:] dans votre expression régulière sed.
WMR
Autre remarque: cela ne fonctionne qu'avec les versions sed> = 4, les versions plus petites ne prennent pas en charge l'édition sur place.
WMR
1
Cela a cassé mon git :(
CrabMan
14

Cela a fonctionné pour moi dans OSX 10.5 Leopard, qui n'utilise pas GNU sed ou xargs.

find dir -type f -print0 | xargs -0 sed -i.bak -E "s/[[:space:]]*$//"

Faites juste attention à cela si vous avez des fichiers qui doivent être exclus (je l'ai fait)!

Vous pouvez utiliser -prune pour ignorer certains répertoires ou fichiers. Pour les fichiers Python dans un référentiel git, vous pouvez utiliser quelque chose comme:

find dir -not -path '.git' -iname '*.py'
pojo
la source
Avez-vous une chance de clarifier cela? Je voudrais une commande qui supprimera les espaces blancs de fin de tous les fichiers d'un répertoire de manière récursive, tout en ignorant le répertoire ".git". Je ne peux pas tout à fait suivre votre exemple ...
Trevor Turk
Si vous utilisez tcsh, vous devrez changer les guillemets doubles en guillemets simples. Sinon, vous obtiendrez un "Nom de variable illégal". Erreur.
Brandon Fosdick
GNU sed est similaire mais vous faites -i.bak ou --in-place = .bak, pour finir avec une commande complète de find dir -not -path '.git' -iname '*.py' -print0 | xargs -0 sed --in-place=.bak 's/[[:space:]]*$//'. Remplacez dirpar le répertoire en question comme niveau supérieur à partir duquel récurer.
David Gardner
sed -i .bak? Ne devrait-il pas être sed -i.bak(sans l'espace)?
Ondra Žižka
9

Ack a été fait pour ce genre de tâche.

Il fonctionne exactement comme grep, mais sait ne pas descendre dans des endroits comme .svn, .git, .cvs, etc.

ack --print0 -l '[ \t]+$' | xargs -0 -n1 perl -pi -e 's/[ \t]+$//'

Beaucoup plus facile que de sauter à travers des cerceaux avec find / grep.

Ack est disponible via la plupart des gestionnaires de paquets (comme ack ou ack-grep ).

C'est juste un programme Perl, il est donc également disponible dans une version à fichier unique que vous pouvez simplement télécharger et exécuter. Voir: Ack Install

jbbuckley
la source
ackest merveilleux. Je l'utilise depuis un certain nombre d'années et est disponible dans presque tous les dépôts de packages pour la plupart des distributions.
Felipe Alvarez
8

ex

Essayez d'utiliser l' éditeur Ex (qui fait partie de Vim):

$ ex +'bufdo!%s/\s\+$//e' -cxa **/*.*

Remarque: Pour la récursivité (bash4 & zsh), nous utilisons une nouvelle option de globbing ( **/*.*). Activer par shopt -s globstar.

Vous pouvez ajouter la fonction suivante dans votre .bash_profile:

# Strip trailing whitespaces.
# Usage: trim *.*
# See: https://stackoverflow.com/q/10711051/55075
trim() {
  ex +'bufdo!%s/\s\+$//e' -cxa $*
}

sed

Pour l'utilisation sed, vérifiez: Comment supprimer les espaces blancs de fin avec sed?

find

Recherchez le script suivant (par exemple remove_trail_spaces.sh) pour supprimer les espaces de fin des fichiers:

#!/bin/sh
# Script to remove trailing whitespace of all files recursively
# See: /programming/149057/how-to-remove-trailing-whitespace-of-all-files-recursively

case "$OSTYPE" in
  darwin*) # OSX 10.5 Leopard, which does not use GNU sed or xargs.
    find . -type f -not -iwholename '*.git*' -print0  | xargs -0 sed -i .bak -E "s/[[:space:]]*$//"
    find . -type f -name \*.bak -print0 | xargs -0 rm -v
    ;;
  *)
    find . -type f -not -iwholename '*.git*' -print0 | xargs -0 perl -pi -e 's/ +$//'
esac

Exécutez ce script à partir du répertoire que vous souhaitez analyser. Sur OSX à la fin, il supprimera tous les fichiers se terminant par .bak.

Ou juste:

find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;

ce qui est recommandé par Spring Framework Code Style .

Kenorb
la source
find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;supprime seulement un espace de fin au lieu de tous.
Karl Richter
6

J'ai fini par ne pas utiliser find et ne pas créer de fichiers de sauvegarde.

sed -i '' 's/[[:space:]]*$//g' **/*.*

En fonction de la profondeur de l'arborescence des fichiers, cette (version plus courte) peut être suffisante pour vos besoins.

REMARQUE cela prend également des fichiers binaires, par exemple.

Jesper Rønn-Jensen
la source
Pour des fichiers spécifiques: recherchez. -nom '* .rb' | xargs -I {} sed -i '' 's / [[: space:]] * $ // g' {}
Gautam Rege
Vous n'avez pas besoin du paramètre «» pour sed; ou je pourrais manquer quelque chose. Je l'ai essayé sur tous les fichiers d'un répertoire donné, comme ceci: sed -i 's / [[: space:]] * $ // g' util / *. M
Mircea
6

Au lieu d'exclure des fichiers, voici une variante de ce qui précède.Les listes blanches explicites des fichiers, en fonction de l'extension de fichier, que vous souhaitez supprimer, n'hésitez pas à assaisonner à votre goût:

find . \( -name *.rb -or -name *.html -or -name *.js -or -name *.coffee -or \
-name *.css -or -name *.scss -or -name *.erb -or -name *.yml -or -name *.ru \) \
-print0 | xargs -0 sed -i '' -E "s/[[:space:]]*$//"
ChicagoBob
la source
Pour que cela fonctionne pour moi, j'avais besoin d'ajouter des citations:-name "*.rb*"
haroldcarr
5

J'ai fini par exécuter ceci, qui est un mélange entre la version pojo et adams.

Il nettoiera à la fois les espaces de fin et également une autre forme d'espaces de fin, le retour chariot:

find . -not \( -name .svn -prune -o -name .git -prune \) -type f \
  -exec sed -i 's/[:space:]+$//' \{} \;  \
  -exec sed -i 's/\r\n$/\n/' \{} \;

Il ne touchera pas le dossier .git s'il y en a un.

Edit : le rend un peu plus sûr après le commentaire, ne permettant pas de prendre des fichiers avec ".git" ou ".svn" dedans. Mais attention, il ne touche pas aux fichiers binaires si vous avez quelques - uns. Utilisez -iname "*.py" -or -iname "*.php"après -type fsi vous voulez seulement qu'il touche par exemple les fichiers .py et .php.

Mise à jour 2 : Il remplace désormais toutes sortes d'espaces en fin de ligne (ce qui signifie également des tabulations)

odinho - Velmont
la source
4
Je ne sais pas ce qui se passe, mais cela a totalement anéanti mon dépôt git et a gâché mes images. LES GENS, SOYEZ PLUS PRUDENT QUE MOI!
mattalxndr
Oui, cela ruinera les fichiers binaires. Cependant, il ne devrait pas du tout toucher votre dépôt git, car il ignore tout ce qui se trouve dans un dossier .git. Mais peut-être seulement si vous êtes dans le même dossier.
odinho - Velmont
4

Cela fonctionne bien .. ajouter / supprimer --include pour des types de fichiers spécifiques:

egrep -rl ' $' --include *.c *  | xargs sed -i 's/\s\+$//g'
Grant Murphy
la source
4

Rubis:

irb
Dir['lib/**/*.rb'].each{|f| x = File.read(f); File.write(f, x.gsub(/[ \t]+$/,"")) }
plus grossier
la source
3

J'utilise des expressions régulières. 4 étapes:

  1. Ouvrez le dossier racine dans votre éditeur (j'utilise Visual Studio Code).
  2. Appuyez sur l'icône de recherche à gauche et activez le mode d'expression régulière.
  3. Entrez "+ \ n" dans la barre de recherche et "\ n" dans la barre de remplacement.
  4. Cliquez sur "Tout remplacer".

Cela supprime tous les espaces de fin à la fin de chaque ligne dans tous les fichiers. Et vous pouvez exclure certains fichiers qui ne correspondent pas à ce besoin.

roedeercuco
la source
2

1) De nombreuses autres réponses utilisent -E. Je ne sais pas pourquoi, car c'est une option de compatibilité BSD non documentée .-rdevrait être utilisé à la place.

2) D'autres réponses utilisent -i ''. Cela devrait être juste -i(ou -i''si préféré), car-i a le suffixe juste après.

3) Solution spécifique à Git:

git config --global alias.check-whitespace \
'git diff-tree --check $(git hash-object -t tree /dev/null) HEAD'

git check-whitespace | grep trailing | cut -d: -f1 | uniq -u -z | xargs -0 sed --in-place -e 's/[ \t]+$//'

Le premier enregistre un alias git check-whitespacequi répertorie les fichiers avec des espaces de fin. Le second courtsed sur eux.

J'utilise uniquement \tplutôt que [:space:]comme je ne vois généralement pas d'onglets verticaux, de flux de formulaires et d'espaces insécables. Votre mesure peut varier.

Ondra Žižka
la source
1

Voici ce qui fonctionne pour moi (Mac OS X 10.8, GNU sed installé par Homebrew):

find . -path ./vendor -prune -o \
  \( -name '*.java' -o -name '*.xml' -o -name '*.css' \) \
  -exec gsed -i -E 's/\t/    /' \{} \; \
  -exec gsed -i -E 's/[[:space:]]*$//' \{} \; \
  -exec gsed -i -E 's/\r\n/\n/' \{} \;

Suppression des espaces de fin, remplace les tabulations par des espaces, remplace Windows CRLF par Unix \n.

Ce qui est intéressant, c'est que je dois l'exécuter 3-4 fois avant que tous les fichiers ne soient corrigés, selon toutes les gsedinstructions de nettoyage .

yegor256
la source