Comment puis-je convertir des tabulations en espaces dans chaque fichier d'un répertoire (éventuellement récursivement)?
Ce n'est généralement pas ce que vous voulez.
Voulez-vous le faire pour les images png? Fichiers PDF? Le répertoire .git? Votre
Makefile
(qui nécessite des onglets)? Un vidage SQL de 5 Go?
Vous pourriez, en théorie, passer un grand nombre d'options d'exclusion vers find
ou tout ce que vous utilisez; mais cela est fragile et se cassera dès que vous ajouterez d'autres fichiers binaires.
Ce que vous voulez, c'est au moins:
- Ignorez les fichiers d'une certaine taille.
- Détectez si un fichier est binaire en vérifiant la présence d'un octet NULL.
- Ne remplacez les onglets qu'au début d'un fichier (
expand
fait cela, sed
pas).
Pour autant que je sache, il n'y a pas d'utilitaire Unix "standard" qui puisse faire cela, et ce n'est pas très facile à faire avec un shell one-liner, donc un script est nécessaire.
Il y a quelque temps, j'ai créé un petit script appelé
sanitize_files qui fait exactement cela. Il corrige également quelques autres trucs communs comme le remplacement \r\n
par \n
, l'ajout d'une fin\n
, etc.
Vous pouvez trouver un script simplifié sans les fonctionnalités supplémentaires et les arguments de ligne de commande ci-dessous, mais je vous recommande d'utiliser le script ci-dessus car il est plus susceptible de recevoir des corrections de bugs et d'autres mises à jour que ce post.
Je voudrais également souligner, en réponse à certaines des autres réponses ici, que l'utilisation de la globalisation du shell n'est pas un moyen robuste de le faire, car tôt ou tard, vous vous retrouverez avec plus de fichiers que ce qui peut en contenir ARG_MAX
(sur les modernes Les systèmes Linux, c'est 128k, ce qui peut sembler beaucoup, mais tôt ou tard ce n'est pas
suffisant).
#!/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)