Jak rekurencyjnie usunąć końcowe białe znaki ze wszystkich plików?


122

Jak usunąć wszystkie końcowe spacje z całego projektu? Rozpoczynając od katalogu głównego i usuwając końcowe białe znaki ze wszystkich plików we wszystkich folderach.

Chciałbym również móc bezpośrednio modyfikować plik, a nie tylko drukować wszystko na standardowe wyjście.


Och, szukasz rozwiązania „przenośnego” czy bardziej specyficznego dla systemu operacyjnego? Z jakiego systemu operacyjnego korzystasz?
Joe Pineda,

3
Bardzo chciałbym zobaczyć wersję tego, która działałaby w systemie OS X Snow Leopard i ignorowałaby foldery .git i .svn.
Trevor Turk

Odpowiedzi:


83

Oto rozwiązanie dla OS X> = 10.6 Snow Leopard.

Ignoruje foldery .git i .svn oraz ich zawartość. Nie pozostawi też pliku kopii zapasowej.

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:]]*$//"

10
Możesz to przyspieszyć, używając \+zamiast *w ciągu zastępczym - w przeciwnym razie pasuje w każdym wierszu.
l0b0

10
Możesz użyć [[: blank:]], aby usunąć zarówno tabulatory, jak i spacje.
Leif Gruenwoldt

21
W Mountain Lion to sed: RE error: illegal byte sequencedla mnie powraca .
Bryson,

12
Dla tych z Was, którzy mają problemy z „niedozwoloną sekwencją bajtów”: wprowadź export LANG=Ci spróbuj ponownie
Georg Ledermann

3
W OS X 10.9 potrzebowałem również, export LC_CTYPE=C jak znalazłem tutaj: stackoverflow.com/questions/19242275/…
kissgyorgy

31

Posługiwać się:

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

jeśli nie chcesz generować plików „.bak”:

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

jako użytkownik zsh możesz pominąć wywołanie funkcji find i zamiast tego użyć:

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

Uwaga: Aby zapobiec niszczeniu .gitkatalogu, spróbuj dodać: -not -iwholename '*.git*'.


37
Nie próbuj tego w repozytorium git, ponieważ może to uszkodzić pamięć wewnętrzną git.
mgold

11
@mgold Za późno, grrr; /
kenorb

3
Aby wyjaśnić, w porządku jest to uruchomić w podfolderze repozytorium git, ale nie w folderach, które zawierają repozytoria git jako potomków, tj. Nie w żadnych folderach, które mają .gitkatalogi, bez względu na to, jak głęboko zagnieżdżone.
Illya Moskvin

Połączenie tej odpowiedzi z @ deepwell's w celu uniknięcia problemów z git / svnfind . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 perl -pi -e 's/ +$//'
William Denniss

1
Prawdopodobnie jest lepszy sposób, ale odzyskałem zdrowie po zniekształceniu repozytorium git, klonując repozytorium w oddzielnym folderze, a następnie robiąc, rsync -rv --exclude=.git repo/ repo2/po czym lokalne zmiany repobyły również w (nieuszkodzone) repo2.
MatrixManAtYrService

29

Dwa alternatywne podejścia, które działają również z znakami nowej linii DOS (CR / LF) i całkiem nieźle radzą sobie z unikaniem plików binarnych :

Ogólne rozwiązanie sprawdzające, czy typ MIME zaczyna się od 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)

Rozwiązanie Matta specyficzne dla repozytorium Git, które wykorzystuje-Iopcjęgit greppomijania plików, które Git uważa za binarne:

git grep -I --name-only -z -e '' | xargs -0 sed -i 's/[ \t]\+\(\r\?\)$/\1/'

3
Więc bardzo podoba mi się to rozwiązanie gita. Powinien być naprawdę na szczycie. Nie chcę jednak oszczędzać powrotów karetki. Ale wolę to od tego, które połączyłem w 2010 roku.
odinho - Velmont

Mój git narzeka, że ​​wyrażenie -e jest puste, ale działa świetnie przy użyciu -e '. *'
muirbot

@okor W GNU sedopcja sufiksu do -ijest opcjonalna , ale w BSDsed nie. Ściśle rzecz biorąc, i tak nie jest to konieczne, więc po prostu je usunę.
l0b0

24

W Bash:

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

Uwaga: Jeśli używasz .gitrepozytorium, warto dodać: -not -iwholename '.git'.


To generuje takie błędy dla każdego znalezionego pliku. sed: 1: "dir / file.txt": polecenie a oczekuje \ po którym następuje tekst
iamjwc

Zastąpienie ';' z \; powinno działać. (Również cudzysłowy wokół {} nie są ściśle potrzebne).
agnul

4
Aby usunąć wszystkie białe spacje, a nie tylko spacje, należy zamienić znak spacji na [: spacja:] w wyrażeniu regularnym sed.
WMR

Kolejna uwaga boczna: działa to tylko z wersjami sed> = 4, mniejsze wersje nie obsługują edycji w miejscu.
WMR

1
To złamało mi
dupę

14

To zadziałało dla mnie w OSX 10.5 Leopard, który nie używa GNU sed ani xargs.

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

Po prostu bądź ostrożny, jeśli masz pliki, które muszą zostać wykluczone (tak zrobiłem)!

Możesz użyć -prune, aby zignorować określone katalogi lub pliki. W przypadku plików Pythona w repozytorium git możesz użyć czegoś takiego:

find dir -not -path '.git' -iname '*.py'

Jest jakaś szansa, że ​​mógłbyś to wyjaśnić? Chciałbym otrzymać polecenie, które rekurencyjnie usunie końcowe białe znaki ze wszystkich plików w katalogu, ignorując katalog „.git”. Nie mogę do końca naśladować twojego przykładu ...
Trevor Turk,

Jeśli używasz tcsh, musisz zmienić podwójne cudzysłowy na pojedyncze cudzysłowy. W przeciwnym razie otrzymasz „Niedozwolona nazwa zmiennej”. błąd.
Brandon Fosdick

GNU sed jest podobny, ale robisz -i.bak lub --in-place = .bak, kończąc na pełnym poleceniu find dir -not -path '.git' -iname '*.py' -print0 | xargs -0 sed --in-place=.bak 's/[[:space:]]*$//'. Zastąp dirodpowiednim katalogiem jako katalogiem najwyższego poziomu, z którego ma nastąpić rekurencja.
David Gardner,

sed -i .bak? Czy nie powinno być sed -i.bak(bez spacji)?
Ondra Žižka

9

Ack został stworzony do tego rodzaju zadań.

Działa tak jak grep, ale wie, że nie schodzi do miejsc takich jak .svn, .git, .cvs itp.

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

O wiele łatwiejsze niż przeskakiwanie przez obręcze za pomocą funkcji find / grep.

Ack jest dostępny za pośrednictwem większości menedżerów pakietów (jako Ack lub Ack-Grep ).

To tylko program w Perlu, więc jest również dostępny w wersji jednoplikowej, którą można po prostu pobrać i uruchomić. Zobacz: Ack Install


ackjest wspaniałe. Używam go od wielu lat i jest dostępny w prawie wszystkich repozytoriach pakietów dla większości dystrybucji.
Felipe Alvarez

8

ex

Spróbuj użyć edytora Ex (część Vima):

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

Uwaga: w przypadku rekurencji (bash4 i zsh) używamy nowej opcji globbingu ( **/*.*). Włącz przez shopt -s globstar.

Możesz dodać następującą funkcję do swojego .bash_profile:

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

sed

Aby użyć sed, sprawdź: Jak usunąć końcowe spacje za pomocą seda?

find

Znajdź następujący skrypt (np. remove_trail_spaces.sh) Do usuwania końcowych białych znaków z plików:

#!/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

Uruchom ten skrypt z katalogu, który chcesz przeskanować. W systemie OSX na końcu usunie wszystkie pliki kończące się na .bak.

Lub tylko:

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

co jest zalecane przez Spring Framework Code Style .


find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;usuwa tylko jedną spację na końcu zamiast wszystkich.
Karl Richter

6

Skończyło się na tym, że nie korzystałem z funkcji znajdowania i nie tworzyłem plików kopii zapasowych.

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

W zależności od głębokości drzewa plików ta (krótsza wersja) może być wystarczająca dla Twoich potrzeb.

UWAGA dotyczy to również, na przykład, plików binarnych.


W przypadku określonych plików: znajdź. -name '* .rb' | xargs -I {} sed -i '' 's / [[: space:]] * $ // g' {}
Gautam Rege

Nie potrzebujesz parametru „” dla seda; albo coś może mi umknąć. Wypróbowałem to na wszystkich plikach w podanym katalogu, na przykład: sed -i 's / [[: space:]] * $ // g' util / *. M
Mircea

6

Zamiast wykluczać pliki, oto odmiana powyższej wyraźnie białej listy plików, w oparciu o rozszerzenie pliku, które chcesz usunąć, możesz doprawić do smaku:

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:]]*$//"

Aby to zadziałało, musiałem dodać cytaty:-name "*.rb*"
haroldcarr

5

Skończyło się na tym, że uruchomiłem to, co jest mieszanką wersji pojo i adams.

Wyczyści zarówno końcowe białe znaki, jak i inną formę końcowych białych znaków, powrót karetki:

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

Nie dotknie folderu .git, jeśli taki istnieje.

Edycja : poprawiono trochę bezpieczeństwa po komentarzu, nie pozwalając na pobieranie plików zawierających „.git” lub „.svn”. Ale uwaga, jeśli masz jakieś , będzie dotykać plików binarnych. Użyj -iname "*.py" -or -iname "*.php"after, -type fjeśli chcesz, aby dotyczyło tylko np. Plików .py i .php.

Aktualizacja 2 : Zastępuje teraz wszelkiego rodzaju spacje na końcu linii (co oznacza również tabulatory)


4
Nie wiem, co się dzieje, ale to całkowicie rozwarło moje repozytorium git i zepsuło moje obrazy. LUDZIE, BĄDŹ BARDZIEJ OSTROŻNY NIŻ BYŁEM!
mattalxndr

Tak, zrujnuje pliki binarne. Jednak nie powinien w ogóle dotykać twojego repozytorium git, ponieważ pomija wszystko, co znajduje się w folderze .git. Ale może tylko wtedy, gdy jesteś w tym samym folderze.
odinho

4

To działa dobrze ... dodaj / usuń --include dla określonych typów plików:

egrep -rl ' $' --include *.c *  | xargs sed -i 's/\s\+$//g'

4

Rubin:

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

3

Używam wyrażeń regularnych. 4 kroki:

  1. Otwórz folder główny w swoim edytorze (używam Visual Studio Code).
  2. Stuknij ikonę Szukaj po lewej stronie i włącz tryb wyrażeń regularnych.
  3. Wpisz „+ \ n” na pasku wyszukiwania i „\ n” na pasku zamiany.
  4. Kliknij „Zamień wszystko”.

Spowoduje to usunięcie wszystkich końcowych spacji na końcu każdego wiersza we wszystkich plikach. Możesz też wykluczyć niektóre pliki, które nie spełniają tej potrzeby.


2

1) Wiele innych odpowiedzi używa -E. Nie jestem pewien dlaczego, ponieważ jest to nieudokumentowana opcja zgodności z BSD .-rnależy użyć zamiast tego.

2) Użyj innych odpowiedzi -i ''. To powinno być sprawiedliwe -i(lub -i''jeśli jest to preferowane), ponieważ -ima przyrostek zaraz po.

3) Rozwiązanie specyficzne dla 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]+$//'

Pierwsza z nich rejestruje alias git, check-whitespacektóry zawiera listę plików z końcowymi spacjami. Drugi biegnie sedna nich.

Używam \traczej niż, [:space:]ponieważ zazwyczaj nie widzę pionowych zakładek, kanałów danych i nierozerwalnych spacji. Twój pomiar może się różnić.


1

To działa dla mnie (Mac OS X 10.8, GNU sed zainstalowany przez 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/' \{} \;

Usunięto końcowe spacje, zastąpiono tabulatory spacjami, zastąpiono Windows CRLF systemem Unix \n .

Co ciekawe, muszę uruchamiać to 3-4 razy, zanim wszystkie pliki zostaną naprawione, zgodnie ze wszystkimi gsedinstrukcjami czyszczenia .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.