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 find
oder 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:
- Überspringen Sie Dateien über eine bestimmte Größe.
- Ermitteln Sie, ob eine Datei binär ist, indem Sie prüfen, ob ein NULL-Byte vorhanden ist.
- Ersetzen Sie Tabs nur am Anfang einer Datei (
expand
tut 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\n
durch \n
, das Hinzufügen eines Trailing \n
usw.
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_MAX
moderne 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)