Wie kann ich Tabulatoren in Leerzeichen in jeder Datei eines Verzeichnisses konvertieren?

251

Wie kann ich Tabulatoren in Leerzeichen in jeder Datei eines Verzeichnisses konvertieren (möglicherweise rekursiv)?

Gibt es auch eine Möglichkeit, die Anzahl der Leerzeichen pro Registerkarte festzulegen?

cnd
quelle
Sie möchten Registerkarten in Dateien oder Dateinamen ersetzen?
Cppcoder
3
prist ein wunderbarer Nutzen dafür. Siehe diese Antwort .
Codeforester

Antworten:

69

Warnung: Dies wird Ihr Repo brechen.

Diese werden korrupte Binärdateien , einschließlich derjenigen unter svn, .git! Lesen Sie die Kommentare vor der Verwendung!

find . -iname '*.java' -type f -exec sed -i.orig 's/\t/ /g' {} +

Die Originaldatei wird als gespeichert [filename].orig.

Ersetzen Sie '* .java' durch das Dateiende des gesuchten Dateityps. Auf diese Weise können Sie eine versehentliche Beschädigung von Binärdateien verhindern.

Nachteile:

  • Ersetzt Tabs überall in einer Datei.
  • Dies dauert lange, wenn sich in diesem Verzeichnis ein 5-GB-SQL-Speicherauszug befindet.
Martin Beckett
quelle
12
Für visuellen Raum, der eine Mischung aus Tabulatoren und Leerzeichen ist, führt dieser Ansatz zu einer falschen Erweiterung.
Pizza
7
Ich würde auch einen Datei-Matcher hinzufügen, wie zum Beispiel nur für .php-Dateien.
Daniel Luca CleanUnicorn
98
KEIN SED VERWENDEN! Wenn eine Zeichenfolge eine eingebettete Registerkarte enthält, kann es sein, dass Sie Ihren Code beschädigen. Dies ist, was der Befehl expand behandeln sollte. Verwenden Sie expand.
David W.
5
@ DavidW. Ich würde diesen Befehl einfach aktualisieren, um nur Tabulatoren am Zeilenanfang zu ersetzen. find ./ -type f -exec sed -i 's/^\t/####/g' {} \;. Der Befehl expand war mir jedoch nicht bekannt - sehr nützlich!
Martin Konecny
29
VERWENDE NICHT! Diese Antwort hat auch gerade mein lokales Git-Repository zerstört. Wenn Sie Dateien mit gemischten Tabulatoren und Leerzeichen haben, werden Sequenzen von # eingefügt. Verwenden Sie stattdessen die Antwort von Gene oder den Kommentar von Doge unten.
Puppe
344

Ein einfacher Austausch durch sedist in Ordnung, aber nicht die bestmögliche Lösung. Wenn zwischen den Registerkarten "zusätzliche" Leerzeichen vorhanden sind, sind diese nach dem Ersetzen noch vorhanden, sodass die Ränder unregelmäßig sind. In der Mitte der Zeilen erweiterte Registerkarten funktionieren ebenfalls nicht richtig. In bashkönnen wir stattdessen sagen

find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;

auf expandjede Java-Datei im aktuellen Verzeichnisbaum anzuwenden . Entfernen / ersetzen Sie das -nameArgument, wenn Sie auf andere Dateitypen abzielen. Seien Sie, wie in einem der Kommentare erwähnt, sehr vorsichtig, wenn Sie -nameeinen schwachen Platzhalter entfernen oder verwenden. Sie können das Repository und andere versteckte Dateien problemlos ohne Absicht löschen. Aus diesem Grund enthielt die ursprüngliche Antwort Folgendes:

Sie sollten immer eine Sicherungskopie des Baums erstellen, bevor Sie so etwas versuchen, falls etwas schief geht.

Gen
quelle
2
@ JeffreyMartinez Gute Frage. gniourf_gniourf hat meine ursprüngliche Antwort am 11. November bearbeitet und abfällige Bemerkungen darüber gemacht, dass ich nicht weiß, wie ich sie richtig verwenden soll {}. Sieht so aus, als hätte er nicht gewusst, $0wann -ces verwendet wird. Dann änderte sich dimo414 von meiner Verwendung einer temporären Datei im Konvertierungsverzeichnis zu /tmp, die viel langsamer ist, wenn sie /tmpsich auf einem anderen Einhängepunkt befindet. Leider habe ich keine Linux-Box zur Verfügung, um Ihren $0Vorschlag zu testen . Aber ich denke du hast recht.
Gene
1
@Gene, danke für die Klarstellung, das klingt nach Stackoverflow in Ordnung: p. Während ich dabei bin, werde ich hinzufügen, dass ich Anführungszeichen um '* .java' verwenden musste, um die * .java richtig zu entkommen.
Jeffrey Martinez
2
Wenn jemand einen 'unbekannten Primär- oder Operator'-Fehler beim Finden hat, dann ist hier der vollständige Befehl, der ihn behebt:find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
Doge
4
Ich dachte, diese Antwort hätte nicht genug Kommentare, also ist dies meine: Wenn Sie die Verwendung spongevon joeyh.name/code/moreutils verwenden , können Sie schreibenfind . -name '*.py' ! -type d -exec bash -c 'expand -t 8 "$0" | sponge "$0"' {} \;
tokland
8
Sei nicht dumm und benutze find . -name '*', ich habe gerade mein lokales Git-Repo zerstört
Gautam
193

Probieren Sie das Befehlszeilenprogramm aus expand.

expand -i -t 4 input | sponge output

wo

  • -i wird verwendet, um nur führende Registerkarten in jeder Zeile zu erweitern.
  • -t 4 bedeutet, dass jede Registerkarte in 4 Leerzeichen umgewandelt wird (standardmäßig 8).
  • spongeist aus dem moreutilsPaket und vermeidet das Löschen der Eingabedatei .

Schließlich können Sie es gexpandnach der Installation coreutilsmit Homebrew ( brew install coreutils) unter OSX verwenden .

kev
quelle
5
Es ist eines von GNU_Core_Utilities
kev
32
Sie sollten an übergeben -i, expandum nur führende Registerkarten in jeder Zeile zu ersetzen. Auf diese Weise wird vermieden, dass Registerkarten ersetzt werden, die möglicherweise Teil des Codes sind.
Quolonel Fragen
10
Wie wäre es für jede einzelne Datei in einem Verzeichnis rekursiv?
Ahnbizcad
4
Jedes Mal, wenn ich versuche, dies zu verwenden, werden einige (normalerweise alle) Dateien gelöscht. : \
ThorSummoner
5
@ThorSummoner: Wenn inputes sich um dieselbe Datei handelt wie outputdie Bash, wird der Inhalt bereits vor dem Start blockiert expand. So >funktioniert es.
Robert Siemer
34

Das Sammeln der besten Kommentare aus Gens Antwort , die mit Abstand beste Lösung, ist die Verwendung spongevon moreutils .

sudo apt-get install moreutils
# The complete one-liner:
find ./ -iname '*.java' -type f -exec bash -c 'expand -t 4 "$0" | sponge "$0"' {} \;

Erläuterung:

  • ./ sucht rekursiv aus dem aktuellen Verzeichnis
  • -inameist eine Übereinstimmung ohne Berücksichtigung der Groß- und Kleinschreibung (für beide *.javaund *.JAVALikes)
  • type -f findet nur reguläre Dateien (keine Verzeichnisse, Binärdateien oder Symlinks)
  • -exec bash -c Führen Sie für jeden Dateinamen die folgenden Befehle in einer Unterschale aus: {}
  • expand -t 4 erweitert alle TABs auf 4 Leerzeichen
  • spongeNehmen Sie die Standardeingabe (von expand) auf und schreiben Sie in eine Datei (dieselbe) *.

HINWEIS : * Eine einfache Dateiumleitung ( > "$0") funktioniert hier nicht, da die Datei zu früh überschrieben wird .

Vorteil : Alle ursprünglichen Dateiberechtigungen bleiben erhalten und es werden keine Zwischendateien tmpverwendet.

not2qubit
quelle
2
TIL: Der wunderbare Schwammbefehl nach 15 Jahren Linux. Vielen Dank, mysteriöser Ritter aus dem Internet.
sscarduzio
19

Verwenden Sie Backslash-Escape sed.

Unter Linux:

  • Ersetzen Sie alle Registerkarten in allen * .txt-Dateien durch einen Bindestrich:

    sed -i $'s/\t/-/g' *.txt
  • Ersetzen Sie alle Registerkarten in allen * .txt-Dateien durch 1 Leerzeichen:

    sed -i $'s/\t/ /g' *.txt
  • Ersetzen Sie alle Registerkarten durch 4 Leerzeichen in allen * .txt-Dateien:

    sed -i $'s/\t/    /g' *.txt

Auf einem Mac:

  • Ersetzen Sie alle Registerkarten durch 4 Leerzeichen in allen * .txt-Dateien:

    sed -i '' $'s/\t/    /g' *.txt
e9t
quelle
2
@ Машаsed -i '' $'s/\t/ /g' $(find . -name "*.txt")
xyzale
Diese Antwort scheint die einfachste zu sein.
Yan King Yin
6

Sie können den allgemein verfügbaren prBefehl verwenden (Manpage hier ). Gehen Sie folgendermaßen vor, um Tabulatoren in vier Leerzeichen zu konvertieren:

pr -t -e=4 file > file.expanded
  • -t unterdrückt Header
  • -e=numErweitert Tabulatoren zu numLeerzeichen

So konvertieren Sie alle Dateien in einem Verzeichnisbaum rekursiv, während Sie Binärdateien überspringen:

#!/bin/bash
num=4
shopt -s globstar nullglob
for f in **/*; do
  [[ -f "$f" ]]   || continue # skip if not a regular file
  ! grep -qI "$f" && continue # skip binary files
  pr -t -e=$num "$f" > "$f.expanded.$$" && mv "$f.expanded.$$" "$f"
done

Die Logik zum Überspringen von Binärdateien stammt aus diesem Beitrag .

HINWEIS:

  1. Dies könnte in einem Git oder SVN Repo gefährlich sein
  2. Dies ist nicht die richtige Lösung, wenn Sie Codedateien haben, in die Registerkarten in Zeichenfolgenliteralen eingebettet sind
Codeforester
quelle
1
Gibt es einen Vorteil gegenüber der expandTatsache, dass beide POSIX sind? Hat es beispielsweise eine Inline-Änderungsoption? Git Sicherheit unter: stackoverflow.com/a/52136507/895245
Ciro Santilli 法轮功 冠状 病 六四 事件 2
5

Wie kann ich Tabulatoren in Leerzeichen in jeder Datei eines Verzeichnisses konvertieren (möglicherweise rekursiv)?

Dies ist normalerweise nicht das, was Sie wollen.

Möchten Sie dies für PNG-Bilder tun? PDF-Dateien? Das .git-Verzeichnis? Ihre Makefile(für die Tabs erforderlich sind )? Ein 5 GB SQL Dump?

Theoretisch könnten Sie eine ganze Reihe von Ausschlussoptionen an findoder was auch immer Sie sonst verwenden, übergeben. Dies ist jedoch fragil und wird unterbrochen, sobald Sie andere Binärdateien hinzufügen.

Was Sie wollen, ist zumindest:

  1. Überspringen Sie Dateien über eine bestimmte Größe.
  2. Ermitteln Sie, ob eine Datei binär ist, indem Sie prüfen, ob ein NULL-Byte vorhanden ist.
  3. Ersetzen Sie Tabs nur am Anfang einer Datei ( expandtut dies, sed tut es nicht).

Soweit ich weiß, gibt es kein "Standard" -Unix-Dienstprogramm, das dies kann, und es ist nicht sehr einfach, mit einem Shell-Einzeiler zu arbeiten, daher wird ein Skript benötigt.

Vor einiger Zeit habe ich ein kleines Skript namens sanitize_files erstellt, das genau das tut. Es behebt auch einige andere häufig auftretende Probleme wie das Ersetzen \r\ndurch \n, das Hinzufügen eines Trailing \nusw.

Sie können ein vereinfachtes Skript ohne die zusätzlichen Funktionen und Befehlszeilenargumente finden, aber ich empfehle Ihnen, das obige Skript zu verwenden, da es mit größerer Wahrscheinlichkeit Bugfixes und andere aktualisierte als diesen Beitrag erhält.

Als Antwort auf einige der anderen Antworten möchte ich auch darauf hinweisen, dass die Verwendung von Shell-Globbing keine robuste Methode ist, da Sie früher oder später mehr Dateien haben, als in die ARG_MAXmoderne Version passen Linux-Systeme sind 128k, was viel zu sein scheint, aber früher oder später ist es nicht genug).


#!/usr/bin/env python
#
# http://code.arp242.net/sanitize_files
#

import os, re, sys


def is_binary(data):
    return data.find(b'\000') >= 0


def should_ignore(path):
    keep = [
        # VCS systems
        '.git/', '.hg/' '.svn/' 'CVS/',

        # These files have significant whitespace/tabs, and cannot be edited
        # safely
        # TODO: there are probably more of these files..
        'Makefile', 'BSDmakefile', 'GNUmakefile', 'Gemfile.lock'
    ]

    for k in keep:
        if '/%s' % k in path:
            return True
    return False


def run(files):
    indent_find = b'\t'
    indent_replace = b'    ' * indent_width

    for f in files:
        if should_ignore(f):
            print('Ignoring %s' % f)
            continue

        try:
            size = os.stat(f).st_size
        # Unresolvable symlink, just ignore those
        except FileNotFoundError as exc:
            print('%s is unresolvable, skipping (%s)' % (f, exc))
            continue

        if size == 0: continue
        if size > 1024 ** 2:
            print("Skipping `%s' because it's over 1MiB" % f)
            continue

        try:
            data = open(f, 'rb').read()
        except (OSError, PermissionError) as exc:
            print("Error: Unable to read `%s': %s" % (f, exc))
            continue

        if is_binary(data):
            print("Skipping `%s' because it looks binary" % f)
            continue

        data = data.split(b'\n')

        fixed_indent = False
        for i, line in enumerate(data):
            # Fix indentation
            repl_count = 0
            while line.startswith(indent_find):
                fixed_indent = True
                repl_count += 1
                line = line.replace(indent_find, b'', 1)

            if repl_count > 0:
                line = indent_replace * repl_count + line

        data = list(filter(lambda x: x is not None, data))

        try:
            open(f, 'wb').write(b'\n'.join(data))
        except (OSError, PermissionError) as exc:
            print("Error: Unable to write to `%s': %s" % (f, exc))


if __name__ == '__main__':
    allfiles = []
    for root, dirs, files in os.walk(os.getcwd()):
        for f in files:
            p = '%s/%s' % (root, f)
            if do_add:
                allfiles.append(p)

    run(allfiles)
Martin Tournoij
quelle
Innerhalb von Git ist die Binärprüfung
Ciro Santilli 郝海东 冠状 病. 事件 法轮功
5

Ich mag das Beispiel "find" oben für die rekursive Anwendung. Um es so anzupassen, dass es nicht rekursiv ist und nur Dateien im aktuellen Verzeichnis ändert, die einem Platzhalter entsprechen, kann die Shell-Glob-Erweiterung für kleine Mengen von Dateien ausreichen:

ls *.java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v

Wenn Sie möchten, dass es stumm geschaltet wird, nachdem Sie darauf vertraut haben, dass es funktioniert, lassen Sie -vden shBefehl am Ende einfach fallen .

Natürlich können Sie im ersten Befehl einen beliebigen Satz von Dateien auswählen. Listen Sie beispielsweise nur ein bestimmtes Unterverzeichnis (oder Verzeichnisse) auf kontrollierte Weise wie folgt auf:

ls mod/*/*.php | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh

Oder führen Sie wiederum find (1) mit einer Kombination von Tiefenparametern usw .:

find mod/ -name '*.php' -mindepth 1 -maxdepth 2 | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
drchuck
quelle
1
Das Shell-Globbing wird früher oder später unterbrochen, da die Gesamtanzahl der Dateinamen nur von ARG_MAXLänge sein kann. Auf Linux-Systemen sind dies 128 KB, aber ich habe diese Grenze oft genug erreicht, um mich nicht auf Shell-Globbing zu verlassen.
Martin Tournoij
1
Sie müssen sie nicht wirklich anpassen. findkann gesagt werden -maxdepth 1, und es verarbeitet nur die Einträge des Verzeichnisses, das geändert wird, nicht den gesamten Baum.
ShadowRanger
4

Ich habe astylemeinen gesamten C / C ++ - Code erneut eingerückt, nachdem ich gemischte Tabulatoren und Leerzeichen gefunden hatte. Es gibt auch Optionen, um einen bestimmten Klammerstil zu erzwingen, wenn Sie möchten.

Theo Belaire
quelle
4

Man kann dafür verwenden vim:

find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;

Wie Carpetsmoker angegeben hat, wird es gemäß Ihren vimEinstellungen retab . Und Modelines in den Dateien, falls vorhanden. Außerdem werden Registerkarten nicht nur am Zeilenanfang ersetzt. Welches ist nicht das, was Sie im Allgemeinen wollen. Beispielsweise könnten Sie Literale haben, die Tabulatoren enthalten.

x-yuri
quelle
:retabändert alle Registerkarten in einer Datei, nicht die am Anfang. es hängt auch davon ab , was Ihre :tabstopund :expandtabEinstellungen sind in den vimrc oder Modeline , so kann dies überhaupt nicht arbeiten.
Martin Tournoij
@Carpetsmoker Guter Punkt zu Tabs am Zeilenanfang. Behandelt eine der hier aufgeführten Lösungen diesen Fall? Was die tabstopund expandtabEinstellungen betrifft, wird es funktionieren, wenn Sie verwenden vim. Es sei denn, Sie haben Moduszeilen in den Dateien.
X-Yuri
@ x-yuri gute Frage, aber im Allgemeinen strittig. Die meisten Leute verwenden keine tatsächlichen Tabulatoren in Literalen.
Ricardo Cruz
4

Meine Empfehlung ist zu verwenden:

find . -name '*.lua' -exec ex '+%s/\t/  /g' -cwq {} \;

Bemerkungen:

  1. Verwenden Sie die In-Place-Bearbeitung. Bewahren Sie Backups in einem VCS auf. Es müssen keine * .orig-Dateien erstellt werden. Es ist empfehlenswert, das Ergebnis von Ihrem letzten Commit zu unterscheiden, um sicherzustellen, dass dies auf jeden Fall wie erwartet funktioniert.
  2. sedist ein Stream-Editor. Verwenden Sie exfür die an Ort und Stelle bearbeiten. Dadurch wird vermieden, dass für jeden Ersatz zusätzliche temporäre Dateien und Spawning-Shells wie in der oberen Antwort erstellt werden .
  3. WARNUNG: Dies beeinträchtigt alle Registerkarten, nicht nur die zum Einrücken verwendeten. Außerdem werden keine Registerkarten kontextsensitiv ersetzt. Dies war ausreichend für meinen Anwendungsfall. Aber vielleicht nicht akzeptabel für Sie.
  4. BEARBEITEN: Eine frühere Version dieser Antwort wird find|xargsanstelle von verwendet find -exec. Wie von @ gniourf-gniourf hervorgehoben, führt dies zu Problemen mit Leerzeichen, Anführungszeichen und Steuerzeichen in Dateinamen, vgl. Wheeler .
Heinrich Hartmann
quelle
exist möglicherweise nicht auf jedem Unix-System verfügbar. Das Ersetzen durch vi -ekönnte auf mehr Maschinen funktionieren. Außerdem ersetzt Ihre Regex eine beliebige Anzahl von Zeichen auf der Startregisterkarte durch zwei Leerzeichen. Ersetzen Sie den regulären Ausdruck durch +%s/\t/ /g, ohne die mehrstufige Einrückung zu zerstören. Dies betrifft jedoch auch Tabulatorzeichen, die nicht zum Einrücken verwendet werden.
Lukas Schmelzeisen
ex ist Teil von POSIX [1] und sollte daher verfügbar sein. Guter Punkt zur mehrstufigen Indendation. Ich hatte die /\t/ /Variante tatsächlich für meine Dateien verwendet, mich jedoch dafür entschieden /\t\+//, nicht einrückende Registerkarten nicht zu beschädigen. Verpasste die Probleme mit Multi-Indentation! Antwort aktualisieren. [1] man7.org/linux/man-pages/man1/ex.1p.html#SEE%C2%A0ALSO
Heinrich Hartmann
2
Die Verwendung xargsauf diese Weise ist nutzlos, ineffizient und fehlerhaft (denken Sie an Dateinamen, die Leerzeichen oder Anführungszeichen enthalten). Warum Sie nicht verwenden find‚s - -execOption statt?
gniourf_gniourf
Ich würde argumentieren, dass Dateinamen mit Leerzeichen und Anführungszeichen fehlerhaft sind. ) Wenn Sie das unterstützen müssen, würde ich mich entscheiden für: -print0Optionen zum Finden von / xargs. Ich mag xargs -execseit: a) Trennung von Bedenken b) es kann leichter mit GNU parallel ausgetauscht werden.
Heinrich Hartmann
Das Hinzufügen von @ gniourf_gniourf-Kommentaren wurde aktualisiert.
Heinrich Hartmann
4

So konvertieren Sie alle Java-Dateien rekursiv in ein Verzeichnis, um 4 Leerzeichen anstelle einer Registerkarte zu verwenden:

find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;
Raffi Khatchadourian
quelle
Wie wird diese Antwort unterscheidet sich von dieser , die wurde vor 4 Jahren geschrieben?
PP
2
Ihre Antwort auch. Tatsächlich ist dies eine minderwertige Version von Gens Antwort: 1) Gens Antwort kümmert sich um Verzeichnisse mit demselben Namen. 2) Es bewegt sich nicht , wenn die Erweiterung fehlgeschlagen ist.
PP
4

Sie können findmit verwendentabs-to-spaces Paket dafür verwenden.

Installieren Sie zuerst tabs-to-spaces

npm install -g tabs-to-spaces

Führen Sie diesen Befehl dann im Stammverzeichnis Ihres Projekts aus.

find . -name '*' -exec t2s --spaces 2 {} \;

Dadurch wird jedes tabZeichen spacesin jeder Datei durch 2 ersetzt .

Harte Vakharia
quelle
3

Kein Körper erwähnt rpl? Mit rpl können Sie eine beliebige Zeichenfolge ersetzen. Um Tabulatoren in Leerzeichen umzuwandeln,

rpl -R -e "\t" "    "  .

sehr einfach.

PeopleMoutainPeopleSea
quelle
1
Dies hat alle Binärdateien in meinem Repo beschädigt.
Aaron Franke
1
Ein ausgezeichneter Befehl, aber möglicherweise gefährlich mit der oben angegebenen Option für rekursive und alle Dateien im Ordner. Ich würde die Option --dry-run "nur für den Fall" hinzufügen, um sicherzustellen, dass Sie im richtigen Ordner sitzen.
MortimerCat
2

Die Verwendung von, expandwie in anderen Antworten vorgeschlagen, scheint der logischste Ansatz für diese Aufgabe allein zu sein.

Dies kann jedoch auch mit Bash und Awk durchgeführt werden, falls Sie weitere Änderungen vornehmen möchten.

Wenn Sie Bash 4.0 oder höher verwenden, können Sie mit dem integrierten shopt globstar rekursiv suchen **.

Mit GNU Awk Version 4.1 oder höher können sed-ähnliche "Inplace" -Dateimodifikationen vorgenommen werden:

shopt -s globstar
gawk -i inplace '{gsub("\t","    ")}1' **/*.ext

Wenn Sie die Anzahl der Leerzeichen pro Registerkarte festlegen möchten:

gawk -i inplace -v n=4 'BEGIN{for(i=1;i<=n;i++) c=c" "}{gsub("\t",c)}1' **/*.ext
John B.
quelle
2

Laden Sie das folgende Skript herunter und führen Sie es aus, um harte Registerkarten in Nur-Text-Dateien rekursiv in weiche Registerkarten zu konvertieren.

Führen Sie das Skript in dem Ordner aus, der die Nur-Text-Dateien enthält.

#!/bin/bash

find . -type f -and -not -path './.git/*' -exec grep -Iq . {} \; -and -print | while read -r file; do {
    echo "Converting... "$file"";
    data=$(expand --initial -t 4 "$file");
    rm "$file";
    echo "$data" > "$file";
}; done;
Daka
quelle
2

Git Repository freundliche Methode

git-tab-to-space() (
  d="$(mktemp -d)"
  git grep --cached -Il '' | grep -E "${1:-.}" | \
    xargs -I'{}' bash -c '\
    f="${1}/f" \
    && expand -t 4 "$0" > "$f" && \
    chmod --reference="$0" "$f" && \
    mv "$f" "$0"' \
    '{}' "$d" \
  ;
  rmdir "$d"
)

Auf alle Dateien im aktuellen Verzeichnis einwirken:

git-tab-to-space

Nur auf C- oder C ++ - Dateien einwirken:

git-tab-to-space '\.(c|h)(|pp)$'

Sie möchten dies wahrscheinlich vor allem wegen der nervigen Makefiles, für die Registerkarten erforderlich sind.

Der Befehl git grep --cached -Il '':

  • listet nur die verfolgten Dateien auf, also nichts drin .git
  • schließt Verzeichnisse, Binärdateien (würde beschädigt sein) und Symlinks (würde in reguläre Dateien konvertiert) aus;

wie unter erklärt: Wie liste ich alle Textdateien (nicht binär) in einem Git-Repository auf?

chmod --referencebehält die Dateiberechtigungen unverändert bei: /unix/20645/clone-ownership-and-permissions-from-another-file Leider kann ich keine prägnante POSIX-Alternative finden .

Wenn Ihre Codebasis die verrückte Idee hatte, funktionale unformatierte Registerkarten in Zeichenfolgen zuzulassen, verwenden Sie:

expand -i

und dann viel Spaß beim Durchgehen aller Registerkarten ohne Zeilenanfang nacheinander, die Sie auflisten können mit: Ist es möglich, grep für Tabs zu aktivieren?

Getestet unter Ubuntu 18.04.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
-1

Konvertieren von Tabulatoren in Leerzeichen nur in ".lua" -Dateien [Tabulatoren -> 2 Leerzeichen]

find . -iname "*.lua" -exec sed -i "s#\t#  #g" '{}' \;
Makah
quelle
Offensichtlich hängt der Speicherplatz, auf den eine Registerkarte erweitert wird, vom Kontext ab. Sed ist daher ein völlig ungeeignetes Werkzeug für die Aufgabe.
Sven
?? @Sven, mein sed Befehl macht das gleiche wie der Befehl expand ( expand -t 4 input >output)
Makah
3
Natürlich nicht. expand -t 4Erweitert die Registerkarte a\tbauf 3 Felder und die Registerkarte aa\tbauf 2 Felder, so wie es sein sollte. expandBerücksichtigt den Kontext einer Registerkarte, sedersetzt die Registerkarte nicht und ersetzt sie durch die von Ihnen angegebene Anzahl von Leerzeichen, unabhängig vom Kontext.
Sven
-1

Verwenden Sie den vim-Weg:

$ ex +'bufdo retab' -cxa **/*.*
  • Machen Sie das Backup! bevor Sie den obigen Befehl ausführen, da er Ihre Binärdateien beschädigen kann.
  • Um globstar( **) für die Rekursion zu verwenden, aktivieren Sie durch shopt -s globstar.
  • Verwenden Sie zum Festlegen eines bestimmten Dateityps beispielsweise : **/*.c.

Fügen Sie hinzu, um Tabstop zu ändern +'set ts=2'.

Der Nachteil ist jedoch, dass es Tabs innerhalb der Zeichenfolgen ersetzen kann .

Versuchen Sie für eine etwas bessere Lösung (durch Substitution):

$ ex -s +'bufdo %s/^\t\+/  /ge' -cxa **/*.*

Oder mit exEditor + expandDienstprogramm:

$ ex -s +'bufdo!%!expand -t2' -cxa **/*.*

Informationen zu nachgestellten Leerzeichen finden Sie unter: So entfernen Sie nachfolgende Leerzeichen für mehrere Dateien.


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

# Convert tabs to spaces.
# Usage: retab *.*
# See: https://stackoverflow.com/q/11094383/55075
retab() {
  ex +'set ts=2' +'bufdo retab' -cxa $*
}
Kenorb
quelle
Ich habe viele Antworten in diesem Thread abgelehnt, nicht nur Ihre ;-) Gründe sind: :retabfunktioniert möglicherweise überhaupt nicht , Shell Globbing ist eine schlechte Lösung für diese Art von Dingen , Ihr :sBefehl ersetzt eine beliebige Anzahl von Tabulatoren durch 2 Leerzeichen (was Sie fast tun nie wollen), ex nur zu starten, um einen :!expandProzess auszuführen , ist dumm ...
Martin Tournoij
... und alle Ihre Lösungen werden Binärdateien und dergleichen (wie PNG-Dateien, PDF-Dateien usw.)
überfallen
Dies ist offen gesagt ein schrecklicher Vorschlag für die Dokumentation - man muss mit einer Reihe von ziemlich undurchsichtigen Syntax- und Semantikproblemen mehrerer Programme vertraut sein, um dies verstehen zu können.
Josip Rodin