Konvertieren von Registerkarten in Leerzeichen in vielen Dateien

11

Ich habe viele Dateien mit Tabs, die überall verstreut sind, und ich möchte sie alle in Leerzeichen konvertieren. Ich kenne den expandBefehl, aber leider müsste ich jede einzelne Datei damit eingeben. Gibt es eine einfachere Möglichkeit, dies unter Linux zu tun?

Person
quelle

Antworten:

12

Versuche Folgendes:

find ./ -type f -exec sed -i 's/\t/ /g' {} \;

Wenn Sie vier Leerzeichen möchten, versuchen Sie:

find ./ -type f -exec sed -i 's/\t/    /g' {} \;
Nicolas Raoul
quelle
Dadurch wird jede Registerkarte durch ein einzelnes Leerzeichen ersetzt. Da die Person die Verwendung erwähnt hat, gehe expandich davon aus, dass die Ausrichtung des Textes erhalten bleiben soll.
Garyjohn
Sie müssen 's/\t/ /g'mehr als nur eine Registerkarte pro Zeile ersetzen.
Daniel Andersson
1
Eine erhebliche Beschleunigung, wenn viele Dateien vorhanden sind, ist " find ./ -type f -exec sed -i ’s/\t/ /g’ {} +" ( dh " +" anstelle von " \;"), wenn die findVersion dies unterstützt (und ich persönlich habe keine Version getroffen, die dies nicht tut, aber es ist kein POSIX-Standard Ich denke, es könnte auf einigen Systemen passieren. Siehe " -exec command {} +" im Handbuch). Anstatt eine Instanz von sedfür jede Datei zu starten , wird eine Argumentliste mit so vielen Dateinamenargumenten erstellt, wie das System unterstützt ( getconf ARG_MAX= 2097152 auf meinem System) xargs, und damit viel weniger sedProzesse gestartet .
Daniel Andersson
6
Hinweis für alle Mac-Benutzer, die dies finden: Die OS X-Version von sedversteht die \tTab-Escape-Sequenz nicht. Sie können es durch ein wörtliches Tabulatorzeichen ersetzen, das Sie in die Shell eingeben können [Ctrl]+V, [Tab].
nicht unter cc by-sa 4.0
expandist wahrscheinlich besser als seddafür, wie erklärt in: stackoverflow.com/a/11094620/131824
David Weinraub
6

Es gibt viele Möglichkeiten, dies zu tun. Es gibt auch viele Möglichkeiten, sich dabei in den Fuß zu schießen, wenn Sie nicht vorsichtig sind oder wenn Sie Linux noch nicht kennen, wie es scheint. Angenommen, Sie können eine Liste von Dateien erstellen, die Sie konvertieren möchten, indem Sie entweder etwas wie findoder manuell mit einem Editor verwenden, und leiten Sie diese Liste einfach in die folgende Liste ein.

while read file
do
   expand "$file" > /tmp/expandtmp
   mv /tmp/expandtmp "$file"
done

Eine Möglichkeit, sich damit in den Fuß zu schießen, besteht darin, einen Tippfehler zu machen, damit Sie eine leere Datei mit allen von Ihnen angegebenen Dateinamen bearbeiten und dadurch den Inhalt aller Ihrer Dateien löschen. Seien Sie also vorsichtig und testen Sie alles, was Sie zuerst tun, an einem kleinen Satz von Dateien, die Sie gesichert haben.

Garyjohn
quelle
3
Machen Sie die mvBedingung vom Erfolg von expand:expand ... && mv ...
Bis auf weiteres angehalten.
Vergessen Sie nicht expand -t 4, die Tabulatoren auf 4 Leerzeichen zu erweitern. Diese Methode kann auch nachfolgende Zeilenumbrüche erstellen. Aber sonst funktioniert es.
mgold
3
find . -type f -iname "*.js" -print0 | xargs -0 -I foo tab2space foo foo

-I foo Erstellt für jede Eingabezeile eine Vorlagenvariable foo, sodass Sie mehrmals auf die Eingabe verweisen können.

-print0und -0weisen Sie beide Befehle an, \ 0 als Zeilentrennzeichen anstelle von SPACE zu verwenden, sodass dieser Befehl für Pfade mit Leerzeichen funktioniert.

Dustin Getz
quelle
1
find -name \*.js -exec bash -c 'expand -t 4 "$0" | tee "$0"' {} \;

Nachteile:
Dateien, die größer als der Pipe-Puffer ( 64 KB ) sind, werden abgeschnitten

Vorteile:
Keine temporären Dateien
, die größer als der Pipe-Puffer sind, werden abgeschnitten

Raylu
quelle
0

Das ist besser:

find . -name *.java ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
oDarek
quelle
3
Warum ist das besser? Es ist keine gute Idee, sie zu verwenden, /tmp/edenn wenn irgendetwas anderes diese Datei verwendet, wird dies sie durcheinander bringen. Zum Beispiel, wenn zwei Benutzer dies gleichzeitig verwenden möchten.
Kevin Panko
0

Ich habe dieses Problem unter Berücksichtigung der folgenden Anforderungen ausprobiert:

  • Filtern Sie die Dateien anhand ihrer Namen, um beispielsweise nur CPP- oder JSON-Dateien zu verarbeiten
  • Unterstützt die parallele Verarbeitung. Wenn es viele Dateien gibt, kann dies eine enorme Beschleunigung bewirken
  • Die Lösung sollte zur einfachen Verwendung in eine Zeile passen

Die letzte Anforderung war am schwierigsten zu erfüllen, da durch "Erweitern" die vorhandenen Dateien nicht geändert werden können.

Ich habe die folgende Lösung gefunden:

find . -type f -regextype egrep -regex '.*\.(c|cpp|h|hpp)'  -print0 | xargs -0 -n 1 -P 10 -IFILE bash -c ' ( echo "Processing FILE..." && expand -t 4 "FILE" > /tmp/expand.$$ && mv /tmp/expand.$$ "FILE" ) || exit 255'

Hier ist eine Erklärung:

  • "find" findet die zu verarbeitenden Dateien. "-regextype egrep" ermöglicht das Filtern nach ihrem Namen und einem regulären Ausdruck im "egrep" -Format
  • Der Parameter "-type f" stellt sicher, dass nur reguläre Dateien übereinstimmen, nicht beispielsweise Verzeichnisse oder andere spezielle Elemente
  • Der Parameter "-regexp" ist der reguläre Ausdruck selbst, der in diesem Fall mit jeder Datei übereinstimmt, die mit .c, .cpp, .h oder .hpp endet (der gesamte Name muss übereinstimmen, damit "file.c2" nicht übereinstimmt , was wir wollen)
  • "-print0" weist "find" an, die Dateipfade in ihrer Standardausgabe mit dem Zeichen 0 am Ende jedes Pfads zu drucken. Zusammen mit der Option "-0" für "xargs" können Namen mit Rückgabewagen von einem Werkzeug zum anderen übergeben werden (auch wenn dies eine ziemlich seltene Situation ist ...)
  • xargs startet einen neuen Prozess für jeden Pfad ("-n 1"), kann jedoch bis zu 10 Prozesse parallel ausführen ("-P 10").
  • xargs verwendet den Alias ​​"FILE", um jeden Dateipfad an den Befehl zu übergeben, bei dem es sich um ein Bash-Skript handelt
  • Das Bash-Skript ruft "expand" auf und speichert das Ergebnis in einer temporären Datei, deren Namen die aktuelle Prozess-ID ($$) enthalten, sodass alle Prozesse, die parallel zu einer bestimmten Datei ausgeführt werden, unterschiedliche temporäre Dateien verwenden
  • Der gesamte Befehl verwendet das Muster (Befehl1 && Befehl2 && Befehl3), sodass der Prozess angehalten wird, wenn ein Unterbefehl einen Fehler zurückgibt
  • Wenn in der vorherigen "&&" -Kette ein Fehler auftritt, gibt das Bash-Skript einen Exit-Code 255 zurück, der dazu führt, dass xargs sofort gestoppt wird
Okroquette
quelle