Wie entferne ich das nachfolgende Leerzeichen aller Dateien rekursiv?

122

Wie können Sie alle nachgestellten Leerzeichen eines gesamten Projekts entfernen? Beginnen Sie in einem Stammverzeichnis und entfernen Sie das nachfolgende Leerzeichen aus allen Dateien in allen Ordnern.

Außerdem möchte ich in der Lage sein, die Datei direkt zu ändern und nicht nur alles auf stdout zu drucken.

iamjwc
quelle
Oh, suchen Sie nach einer "tragbaren" Lösung oder einer betriebssystemspezifischeren? Welches Betriebssystem verwenden Sie?
Joe Pineda
3
Ich würde gerne eine Version davon sehen, die unter OS X Snow Leopard funktioniert und die Ordner .git und .svn ignoriert.
Trevor Turk

Antworten:

83

Hier ist eine OS X> = 10.6 Snow Leopard-Lösung.

Es ignoriert die Ordner .git und .svn und deren Inhalt. Außerdem wird keine Sicherungsdatei hinterlassen.

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:]]*$//"
Tiefbrunnen
quelle
10
Sie können es schneller machen, indem Sie \+anstelle *der Ersatzzeichenfolge verwenden. Andernfalls stimmt es in jeder einzelnen Zeile überein.
10b0
10
Sie können [[: blank:]] verwenden, um sowohl Tabulatoren als auch Leerzeichen zu entfernen.
Leif Gruenwoldt
21
In Mountain Lion kehrt dies sed: RE error: illegal byte sequencefür mich zurück.
Bryson
12
Für diejenigen unter Ihnen, die Probleme mit der "illegalen Byte-Sequenz" haben: Geben Sie ein export LANG=Cund versuchen Sie es erneut
Georg Ledermann
3
In OS X 10.9 brauchte ich auch export LC_CTYPE=C wie hier zu finden: stackoverflow.com/questions/19242275/…
kissgyorgy
31

Verwenden:

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

Wenn Sie nicht möchten, dass die ".bak" -Dateien generiert werden:

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

Als zsh-Benutzer können Sie den Aufruf zum Suchen weglassen und stattdessen Folgendes verwenden:

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

Hinweis: Um zu verhindern, dass das .gitVerzeichnis zerstört wird , fügen Sie Folgendes hinzu : -not -iwholename '*.git*'.

Sec
quelle
37
Versuchen Sie dies nicht in einem Git-Repo, da dies den internen Speicher von Git beschädigen kann.
mgold
11
@mgold Zu spät, grrr; /
Kenorb
3
Zur Verdeutlichung ist es in Ordnung, dies in einem Unterordner eines Git-Repos auszuführen, nur nicht in Ordnern, die Git-Repos als Nachkommen enthalten, dh nicht in Ordnern mit .gitVerzeichnissen, egal wie tief verschachtelt.
Illya Moskvin
Kombinieren Sie diese Antwort mit @ deepwell's, um Git / SVN-Probleme zu vermeidenfind . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 perl -pi -e 's/ +$//'
William Denniss
1
Es gibt wahrscheinlich einen besseren Weg, aber ich habe mich davon erholt, ein Git-Repo damit zu entstellen, indem ich das Repo in einen separaten Ordner geklont habe und danach rsync -rv --exclude=.git repo/ repo2/die lokalen Änderungen in repo(unbeschädigt) vorgenommen habe repo2.
MatrixManAtYrService
29

Zwei alternative Ansätze, die auch mit DOS-Zeilenumbrüchen (CR / LF) funktionieren und bei der Vermeidung von Binärdateien ziemlich gute Arbeit leisten :

Generische Lösung, die überprüft, ob der MIME-Typ beginnt mit 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)

Git-Repository-spezifische Lösung von Mat, die die-IOption verwendetgit grep, Dateien zu überspringen, die Git als binär betrachtet:

git grep -I --name-only -z -e '' | xargs -0 sed -i 's/[ \t]\+\(\r\?\)$/\1/'
l0b0
quelle
3
Also ich mag diese Git-Lösung wirklich. Es sollte wirklich oben sein. Ich möchte jedoch keine Wagenrückläufe speichern. Aber ich ziehe dies dem vor, den ich 2010 kombiniert habe.
Odinho - Velmont
Mein Git beschwert sich, dass der Ausdruck -e leer ist, aber er funktioniert hervorragend mit -e '. *'
muirbot
@okor In GNU sedder Suffix Option -iist optional , aber in BSDsed ist es nicht. Es ist hier streng genommen sowieso nicht notwendig, also werde ich es einfach entfernen.
10.
24

In Bash:

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

Hinweis: Wenn Sie ein .gitRepository verwenden, fügen Sie Folgendes hinzu : -not -iwholename '.git'.

Adam Rosenfield
quelle
Dies erzeugt solche Fehler für jede gefundene Datei. sed: 1: "dir / file.txt": Befehl a erwartet \ gefolgt von Text
iamjwc
Ersetzen von ';' mit \; sollte arbeiten. (Auch Anführungszeichen um {} werden nicht unbedingt benötigt).
Agnul
4
Um alle Leerzeichen und nicht nur Leerzeichen zu entfernen, sollten Sie das Leerzeichen in Ihrem sed-regulären Ausdruck durch [: space:] ersetzen.
WMR
Noch eine Randnotiz: Dies funktioniert nur mit sed-Versionen> = 4, kleinere Versionen unterstützen die direkte Bearbeitung nicht.
WMR
1
Dies hat meinen
Schwachkopf
14

Dies funktionierte für mich in OSX 10.5 Leopard, das weder GNU sed noch xargs verwendet.

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

Seien Sie vorsichtig, wenn Sie Dateien haben, die ausgeschlossen werden müssen (ich habe es getan)!

Mit -prune können Sie bestimmte Verzeichnisse oder Dateien ignorieren. Für Python-Dateien in einem Git-Repository können Sie Folgendes verwenden:

find dir -not -path '.git' -iname '*.py'
Pojo
quelle
Gibt es eine Chance, dies zu klären? Ich möchte einen Befehl, mit dem nachfolgende Leerzeichen rekursiv aus allen Dateien in einem Verzeichnis entfernt werden, während das Verzeichnis ".git" ignoriert wird. Ich kann Ihrem Beispiel nicht ganz folgen ...
Trevor Turk
Wenn Sie tcsh verwenden, müssen Sie die doppelten Anführungszeichen in einfache Anführungszeichen ändern. Andernfalls erhalten Sie einen "Unzulässigen Variablennamen". Error.
Brandon Fosdick
GNU sed ist ähnlich, aber Sie tun -i.bak oder --in-place = .bak, was zu einem vollständigen Befehl von führt find dir -not -path '.git' -iname '*.py' -print0 | xargs -0 sed --in-place=.bak 's/[[:space:]]*$//'. Ersetzen Sie dirdurch das betreffende Verzeichnis als oberste Ebene, aus der Sie zurückkehren können.
David Gardner
sed -i .bak? Sollte es nicht sein sed -i.bak(ohne Platz)?
Ondra Žižka
9

Ack wurde für diese Art von Aufgabe gemacht.

Es funktioniert genau wie grep, kann aber nicht in Orte wie .svn, .git, .cvs usw. absteigen.

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

Viel einfacher als mit find / grep durch Reifen zu springen.

Ack ist über die meisten Paketmanager verfügbar (entweder als ack oder ack-grep ).

Es ist nur ein Perl-Programm, daher ist es auch in einer Einzeldateiversion verfügbar, die Sie einfach herunterladen und ausführen können. Siehe: Installation bestätigen

jbbuckley
quelle
ackist wunderbar. Ich benutze es seit einigen Jahren und bin in fast allen Paket-Repos für die meisten Distributionen erhältlich.
Felipe Alvarez
8

ex

Versuchen Sie es mit dem Ex-Editor (Teil von Vim):

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

Hinweis: Für die Rekursion (bash4 & zsh) verwenden wir eine neue Globbing-Option ( **/*.*). Aktivieren durchshopt -s globstar .

Sie können Ihrer Funktion folgende Funktion hinzufügen .bash_profile:

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

sed

Aktivieren Sie zur Verwendung sedFolgendes: Entfernen von nachgestellten Leerzeichen mit sed?

find

Suchen Sie das folgende Skript (z. B. remove_trail_spaces.sh) zum Entfernen nachfolgender Leerzeichen aus den Dateien:

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

Führen Sie dieses Skript in dem Verzeichnis aus, das Sie scannen möchten. Unter OSX werden am Ende alle Dateien entfernt, die mit enden.bak .

Oder nur:

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

Dies wird übrigens von Spring Framework Code Style empfohlen .

Kenorb
quelle
find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;entfernt nur ein nachfolgendes Leerzeichen anstelle von allen.
Karl Richter
6

Am Ende habe ich find nicht verwendet und keine Sicherungsdateien erstellt.

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

Abhängig von der Tiefe des Dateibaums kann diese (kürzere Version) für Ihre Anforderungen ausreichend sein.

HINWEIS Hierfür werden beispielsweise auch Binärdateien verwendet.

Jesper Rønn-Jensen
quelle
Für bestimmte Dateien: finden. -name '* .rb' | xargs -I {} sed -i '' s / [[: space:]] * $ // g '{}
Gautam Rege
Sie benötigen den Parameter '' nicht für sed; oder mir fehlt etwas. Ich habe es mit allen Dateien in einem bestimmten Verzeichnis versucht, wie folgt: sed -i 's / [[: space:]] * $ // g' util / *. M
Mircea
6

Anstatt Dateien auszuschließen, finden Sie hier eine Variation der oben genannten explizit weißen Listen der Dateien, basierend auf der Dateierweiterung, die Sie entfernen möchten. Sie können sie nach Belieben würzen:

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
quelle
Damit dies für mich funktioniert, musste ich Zitate hinzufügen:-name "*.rb*"
Haroldcarr
5

Am Ende habe ich dies ausgeführt, was eine Mischung aus Pojo und Adams Version ist.

Es werden sowohl nachgestellte Leerzeichen als auch eine andere Form von nachgestellten Leerzeichen, der Wagenrücklauf, bereinigt:

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

Der .git-Ordner wird nicht berührt, wenn es einen gibt.

Bearbeiten : Nach dem Kommentar etwas sicherer gemacht, da keine Dateien mit ".git" oder ".svn" aufgenommen werden dürfen. Aber Vorsicht, es wird Binärdateien berühren, wenn Sie welche haben. Verwenden Sie -iname "*.py" -or -iname "*.php"nach, -type fwenn Sie nur z. B. .py- und .php-Dateien berühren möchten.

Update 2 : Es ersetzt jetzt alle Arten von Leerzeichen am Zeilenende (dh auch Tabulatoren).

Odinho - Velmont
quelle
4
Ich weiß nicht, was los ist, aber das hat mein Git-Repo total durcheinander gebracht und meine Bilder durcheinander gebracht. MENSCHEN, SIND SIE SORGFÄLTIGER ALS ICH!
Mattalxndr
Ja, es werden Binärdateien ruiniert. Es sollte jedoch Ihr Git-Repo überhaupt nicht berühren, da es alles überspringt, was sich in einem .git-Ordner befindet. Aber vielleicht nur, wenn Sie sich im selben Ordner befinden.
Odinho - Velmont
4

Dies funktioniert gut. Hinzufügen / Entfernen - Einschließen für bestimmte Dateitypen:

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

Rubin:

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

Ich benutze reguläre Ausdrücke. 4 Schritte:

  1. Öffnen Sie den Stammordner in Ihrem Editor (ich verwende Visual Studio Code).
  2. Tippen Sie links auf das Suchsymbol und aktivieren Sie den Modus für reguläre Ausdrücke.
  3. Geben Sie "+ \ n" in die Suchleiste und "\ n" in die Ersetzungsleiste ein.
  4. Klicken Sie auf "Alle ersetzen".

Dadurch werden alle nachgestellten Leerzeichen am Ende jeder Zeile in allen Dateien entfernt. Und Sie können einige Dateien ausschließen, die nicht zu diesem Bedarf passen.

roedeercuco
quelle
2

1) Viele andere Antworten verwenden -E. Ich bin mir nicht sicher warum, da dies eine undokumentierte BSD-Kompatibilitätsoption ist .-rsollte stattdessen verwendet werden.

2) Andere Antworten verwenden -i ''. Das sollte gerecht sein -i(oder -i''wenn bevorzugt), weil-i das Suffix direkt danach steht.

3) Git-spezifische Lösung:

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]+$//'

Der erste registriert einen Git-Alias, check-whitespaceder die Dateien mit nachgestellten Leerzeichen auflistet. Der zweite läuftsed auf ihnen.

Ich verwende nur vertikale Tabulatoren, Formular-Feeds und nicht unterbrechbare Leerzeichen, \tanstatt sie [:space:]normalerweise nicht zu sehen. Ihre Messung kann variieren.

Ondra Žižka
quelle
1

Dies funktioniert bei mir (Mac OS X 10.8, GNU sed von Homebrew installiert):

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/' \{} \;

Nachgestellte Leerzeichen entfernt, Tabulatoren durch Leerzeichen ersetzt, Windows CRLF durch Unix ersetzen \n.

Interessant ist, dass ich dies 3-4 Mal ausführen muss, bevor alle Dateien durch alle Reinigungsanweisungen gsedrepariert werden.

yegor256
quelle