Conversion d'onglets en espaces dans de nombreux fichiers

11

J'ai beaucoup de fichiers avec des onglets partout, et je voudrais les convertir tous en espaces. Je connais la expandcommande, mais malheureusement, je devrais taper chaque fichier en l'utilisant. Existe-t-il un moyen plus simple de le faire sous Linux?

la personne
la source

Réponses:

12

Essayez ce qui suit:

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

Si vous voulez quatre espaces, essayez:

find ./ -type f -exec sed -i 's/\t/    /g' {} \;
Nicolas Raoul
la source
Cela remplacera chaque onglet par un seul espace. Puisque la personne a mentionné l'utilisation expand, je suppose qu'elle souhaite que l'alignement du texte soit préservé.
garyjohn
Vous devez 's/\t/ /g'remplacer plus d'un onglet par ligne.
Daniel Andersson
1
Une accélération substantielle s'il y a beaucoup de fichiers fait " find ./ -type f -exec sed -i ’s/\t/ /g’ {} +" (c'est-à-dire " +" au lieu de " \;"), si la findversion le prend en charge (et je n'ai personnellement rencontré aucune version qui ne le fait pas, mais ce n'est pas un standard POSIX , donc je suppose que cela peut arriver sur certains systèmes. Voir " -exec command {} +" dans le manuel). Au lieu de lancer une instance de sedpour chaque fichier, cela va créer une liste d'arguments avec autant d'arguments de nom de fichier que le système prend en charge ( getconf ARG_MAX= 2097152 sur mon système), tout comme xargs, et ainsi lancer beaucoup moins de sedprocessus.
Daniel Andersson
6
Remarque pour tous les utilisateurs de Mac qui trouvent ceci: la version d'OS X de sedne comprend pas la \tséquence d'échappement des onglets. Vous pouvez le remplacer par un caractère de tabulation littéral, que vous pouvez saisir dans le shell par [Ctrl]+V, [Tab].
Jeremy Banks dit RESTER À LA MAISON
expandest probablement mieux que sedpour cela, comme expliqué dans: stackoverflow.com/a/11094620/131824
David Weinraub
6

Il y a plusieurs manières de faire ça. Il existe également de nombreuses façons de se tirer une balle dans le pied tout en faisant cela si vous ne faites pas attention ou si vous êtes nouveau sous Linux comme vous semblez l'être. En supposant que vous pouvez créer une liste de fichiers que vous souhaitez convertir, soit en utilisant quelque chose comme findou manuellement avec un éditeur, il vous suffit de diriger cette liste vers la suivante.

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

Une façon dont vous pouvez vous tirer une balle dans le pied avec cela est de faire une faute de frappe afin de retrouver un fichier vide avec tous les noms de fichiers que vous spécifiez, supprimant ainsi le contenu de tous vos fichiers. Soyez donc prudent et testez tout ce que vous faites en premier sur un petit ensemble de fichiers que vous avez sauvegardés.

garyjohn
la source
3
Faire le mvconditionnel à la réussite de expand:expand ... && mv ...
Suspendu jusqu'à nouvel ordre.
N'oubliez pas expand -t 4d'étendre les tabulations à 4 espaces. En outre, cette méthode peut créer des sauts de ligne de fin. Mais sinon ça marche.
mgold
3
find . -type f -iname "*.js" -print0 | xargs -0 -I foo tab2space foo foo

-I foo crée une variable de modèle foo pour chaque ligne d'entrée, de sorte que vous pouvez vous référer à l'entrée plus d'une fois.

-print0et -0dire aux deux commandes d'utiliser \ 0 comme séparateur de ligne au lieu de SPACE, donc cette commande fonctionne pour les chemins avec des espaces.

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

Inconvénients: les
fichiers plus grands que la taille du tampon de canal ( 64 Ko ) sont tronqués

Avantages:
aucun fichier de
fichiers temporaires plus grand que la taille du tampon de tuyau n'est tronqué

raylu
la source
0

C'est mieux:

find . -name *.java ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
oDarek
la source
3
Pourquoi est-ce mieux? Ce n'est pas une bonne idée à utiliser /tmp/ecar si quelque chose d'autre utilise ce fichier, cela le gâchera. Comme si deux utilisateurs voulaient l'utiliser en même temps.
Kevin Panko
0

J'ai essayé ce problème avec les exigences suivantes à l'esprit:

  • Filtrer les fichiers en fonction de leurs noms, pour traiter par exemple uniquement les fichiers .cpp ou .json
  • Prend en charge le traitement parallèle. Dans le cas où il y a beaucoup de fichiers, cela peut fournir une accélération énorme
  • La solution doit tenir sur une seule ligne pour une utilisation facile

La dernière exigence était la plus difficile à remplir car "développer" ne permet pas de modifier les fichiers en place.

J'ai trouvé la solution suivante:

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'

Voici quelques explications:

  • "find" trouve les fichiers à traiter. "-regextype egrep" permet de les filtrer en fonction de leur nom et d'une expression régulière au format "egrep"
  • le paramètre "-type f" s'assure que nous ne correspondrons qu'aux fichiers normaux, pas aux répertoires par exemple ou à quoi que ce soit d'autre
  • le paramètre "-regexp" est l'expression régulière elle-même, qui correspond dans ce cas à tout fichier se terminant par .c, .cpp, .h ou .hpp (le nom entier doit correspondre, donc "file.c2" ne serait pas , c'est ce que nous voulons)
  • "-print0" indique à "find" d'imprimer les chemins de fichier sur sa sortie standard avec le caractère 0 à la fin de chaque chemin. Associé à l'option "-0" pour "xargs", il permet de passer des noms contenant des chariots de retour d'un outil à l'autre (même si c'est une situation assez rare ...)
  • xargs démarre un nouveau processus pour chaque chemin ("-n 1"), mais peut exécuter jusqu'à 10 processus en parallèle ("-P 10")
  • xargs utilise l'alias "FILE" pour passer chaque chemin de fichier à la commande, qui est un script bash
  • le script bash appelle "expand" et enregistre le résultat dans un fichier temporaire dont les noms contiennent l'ID de processus actuel ($$), de sorte que tous les processus s'exécutant en parallèle sur un fichier donné utilisent des fichiers temporaires différents
  • la commande entière utilise le modèle (command1 && command2 && command3) afin que le processus s'arrête si une sous-commande renvoie une erreur
  • s'il y a une erreur de la chaîne "&&" précédente, le script bash renverra un code de sortie 255 qui provoquera l'arrêt immédiat de xargs
ocroquette
la source