J'ai hérité de cet extrait de script SED qui tente de supprimer certains espaces vides: qui fonctionne sur un fichier d'environ 1 Go de grande taille. Ce script fonctionne pendant 2 heures sur notre serveur UNIX. Des idées comment accélérer? p> Notes que le \ S signifie qu'un espace et \ t représente un onglet, le script actuel utilise l'espace et l'onglet réels et non de ces symboles forts> p> Le fichier d'entrée est un fichier délimité de tuyau et se trouve localement non sur le réseau. Les 4 lignes sont dans un fichier exécuté avec sed -f p> p>
11 Réponses :
Il me semble que vous me semble à partir de votre exemple, vous nettoyez l'espace blanc depuis le début et la fin des champs délimités (|) dans un fichier texte. Si je devais faire cela, je changerais l'algorithme en ce qui suit:
for each line split the line into an array of fields remove the leading and trailing white space join the fields back back together as a pipe delimited line handling the empty first field correctly.
Pouvez-vous suggérer une commande awk pour faire cela? Désolé pas un expert awk
J'ai testé cet algorithme en utilisant AWK (dans le même sens que les programmes AWK proposés par D. Williamson et LevisleVvis85), et il était un peu plus lent que le script SED de l'OP et un peu plus lent que les versions optimisées du script SED. Donc, je ne suis pas convaincu que cette approche générale (de diviser les enregistrements dans des champs avant la substitution de la structure) devrait entraîner une vitesse de vitesse (quelle que soit la langue).
Essayez de changer les deux premières lignes à:
Mes tests n'ont trouvé aucune différence entre cela et les faire séparément.
Mon test a trouvé cela pour diminuer le temps nécessaire pour analyser un fichier de 250 Mo. J'ai également trouvé une nouvelle diminution en éliminant les options g code> où ce n'est pas nécessaire.
Essayez de le faire dans une commande:
sed 's/[^|]*(|.*|).*/\1/'
Pouvez-vous fournir des données de test? Il est difficile d'écrire correctement une regexp sans tests :)
Avez-vous essayé Perl? Cela peut être plus rapide.
#!/usr/local/bin/perl -p s#[\t ]+\|#|#g; s#\|[\t ]+#|#g; s#[\t ]*$##; s#^\|#null|#;
Ce script Perl devrait être beaucoup plus rapide essentiellement, assurez-vous que vos regex sont compilés une fois (le drapeau "O ') et non besoin d'utiliser" g "sur les regexes qui s'appliquent uniquement à la fin et au début de la ligne. p> aussi, [\ s \ t] * est équivalent à \ s * p> p>
Le drapeau "O" est redondant dans ce contexte. Perl compile toujours une nouvelle fois une refonte une fois que cela a une variable à l'intérieur.
Cela pourrait fonctionner. J'ai seulement testé un peu.
Les tests préliminaires montrent cela pour exécuter à peu près à la même vitesse que les versions sed code>.
Que diriez-vous de Perl: EDIT: Approche modifiée de manière significative. Sur ma machine, cela est presque 3 fois plus rapide que votre script SED. P> Si vous avez vraiment besoin de la meilleure vitesse possible, écrivez un programme C spécialisé pour effectuer cette tâche. P> P>
Sur ma machine, il est un peu plus lent que le script SED de l'OP et prend deux fois aussi longtemps qu'une version plus optimisée du script SED de OP.
Utilisez GAWK, pas SED.
awk -vFS='|' '{for(i=1;i<=NF;i++) gsub(/ +|\t+/,"",$i)}1' OFS="|" file
Mes tests ont indiqué que sed code> peut devenir un processeur lié assez facilement sur quelque chose comme ça. Si vous avez une machine multi-noyau, vous pouvez essayer de frai plusieurs processus code> SED CODE> avec un script qui ressemble à ceci:
#!/bin/sh
INFILE=data.txt
OUTFILE=fixed.txt
SEDSCRIPT=script.sed
SPLITLIMIT=`wc -l $INFILE | awk '{print $1 / 20}'`
split -d -l $SPLITLIMT $INFILE x_
for chunk in ls x_??
do
sed -f $SEDSCRIPT $chunk > $chunk.out &
done
wait
cat x_??.out >> output.txt
rm -f x_??
rm -f x_??.out
Utilisation inutile de ls code>. Faites cela à la place:
pour le morceau en x _ ?? code> et le globbing est trié et sans avoir besoin d'une boucle ici:
cat x _ ??. Out> sortie.txt code>
Édité pour inclure les commentaires de Dennis.
Le meilleur que j'ai pu faire avec SED, était ce script: dans mes tests, cela a couru environ 30% plus rapidement que votre script SED. L'augmentation de la performance provient de la combinaison des deux premières fends et d'omettre le drapeau "G" où ce n'est pas nécessaire. P> Cependant, 30% plus rapide n'est qu'une amélioration légère (il devrait toujours prendre environ une heure et un la moitié pour exécuter le script ci-dessus sur votre fichier de données de 1 Go). Je voulais voir si je pouvais mieux faire mieux. P> À la fin, aucune autre méthode que j'ai essayée (AWK, Perl et d'autres approches avec SED) a encore augmenté, sauf - bien sûr - la mise en œuvre ordinaire OL 'C. Comme on pouvait s'y attendre avec c, le code est un peu verbeux pour l'affichage ici, mais si vous voulez un programme susceptible d'être plus rapide que toute autre méthode, vous voudrez peut-être dans mes tests, la mise en œuvre C se termine dans environ 20% du temps nécessaire pour votre SED scénario. Donc, cela peut prendre environ 25 minutes environ pour exécuter votre serveur UNIX. P> Je n'ai pas passé beaucoup de temps à optimiser la mise en œuvre de C. Il ne fait aucun doute qu'il y a plusieurs endroits où l'algorithme pourrait être amélioré, mais franchement, je ne sais pas s'il est possible de raser une durée importante au-delà de ce qu'elle atteint déjà. Si quelque chose, je pense que cela place certainement une limite supérieure sur quel type de performance à laquelle vous pouvez vous attendre d'autres méthodes (SED, AWK, Perl, Python, etc.). P> Strlen () Code> qui lui a donné une autre légère performance Boost. P> P>
+1 Pour une quantité impressionnante de travail pour mettre en œuvre une solution plus rapide et le tester correctement plutôt que de simplement en supposer que ce sera plus rapide.
Je pense que le code> correspond à zéro ou plusieurs éléments suivis par un ne changera que les caractères Je n'ai pas SED disponible, mais j'ai fait une expérience avec Perl. Sur les données, j'ai utilisé le script avec le Les temps étaient cohérents à travers les courses. Pour le Détails de l'expérience forte> p> testé à l'aide d'un fichier de 80 Mo avec un peu plus de 180000 occurrences de Le test a utilisé un fichier de commande de lot avec 30 de chacune de ces deux commandes, une étoile alternée et plus. p> * code> dans les expressions régulières de la question et la plupart des réponses peuvent être un ralentissement majeur par rapport à l'utilisation d'un
+ code>. Considérons le premier remplacement de la question
| code>, d'où chaque
| code> est remplacé même ceux qui n'ont pas besoin de remplacer. Changer le remplacement en être p>
| code> précédé d'un ou plusieurs espaces et onglets. P>
* code> a pris presque 7 fois plus longtemps que le script avec
+ code>. P>
+ code> La différence entre les temps minimum et maximum était de 4% de la moyenne et du
* code> il était de 3,6%. Le rapport entre la moyenne était de 1 :: 6.9 pour
+ code> ::
* code>. P>
[st] \. code>, ce sont les caractères minuscules
S code> et
t code >. p>
c:\test> perl -v
This is perl 5, version 16, subversion 3 (v5.16.3) built for MSWin32-x64-multi-thread
(with 1 registered patch, see perl -V for more detail)
Copyright 1987-2012, Larry Wall
Binary build 1603 [296746] provided by ActiveState http://www.ActiveState.com
Built Mar 13 2013 13:31:10
Comment appelez-vous SED? Est-ce que le fichier est définitivement sur votre disque local et non, disons, sur un montage NFS?
Fichier sur le disque local. J'invoque SED avec sed -f
Veuillez donner la ligne de commande complète que vous utilisez. LIME
SED -F CODE> lit de stdin et écrit à stdout, ce qui n'est évidemment pas ce que vous faites.
Je ne pense pas que ce soit vraiment nécessaire ... supposez simplement
SED -F sortie.txt code>
Je viens d'essayer mon implémentation C sur un fichier de données 1.2GIB rempli d'exemple de données. Il a fallu tous les 4m17 sur un Pentium III de 10 ans de 800 MHz. Bien que cela puisse citer, il peut varier en fonction de la contribution réelle, je pense qu'il y a de bonnes chances que cela dépend de manière significative de votre script SED;)