J'ai un fichier contenant environ 10 millions de lignes.
Je souhaite supprimer toutes les lignes du fichier comportant moins de six caractères.
Comment puis-je faire cela?
Il y a plusieurs façons de le faire.
Utilisation de grep
name__:
grep -E '^.{6,}$' file.txt >out.txt
out.txt
contiendra maintenant des lignes de six caractères ou plus.
Manière inverse:
grep -vE '^.{,5}$' file.txt >out.txt
En utilisant sed
name__, en supprimant les lignes de longueur égale ou inférieure à 5:
sed -r '/^.{,5}$/d' file.txt
En sens inverse, lignes d'impression de longueur supérieure ou égale à six:
sed -nr '/^.{6,}$/p' file.txt
Vous pouvez enregistrer la sortie dans un fichier différent à l'aide de l'opérateur >
tel que grep
ou éditer le fichier sur place à l'aide de l'option -i
de sed
name__:
sed -ri.bak '/^.{6,}$/' file.txt
Le fichier d'origine sera sauvegardé sous le nom file.txt.bak
et le fichier modifié sera file.txt
.
Si vous ne souhaitez pas conserver de sauvegarde:
sed -ri '/^.{6,}$/' file.txt
En utilisant Shell, Plus lentement, ne faites pas ceci, c'est juste pour montrer une autre méthode:
while IFS= read -r line; do [ "${#line}" -ge 6 ] && echo "$line"; done <file.txt
Utilisation de python
name __, même plus lent que grep
name__, sed
name__:
#!/usr/bin/env python2
with open('file.txt') as f:
for line in f:
if len(line.rstrip('\n')) >= 6:
print line.rstrip('\n')
Mieux vaut utiliser la compréhension de la liste pour être plus Pythonique:
#!/usr/bin/env python2
with open('file.txt') as f:
strip = str.rstrip
print '\n'.join([line for line in f if len(strip(line, '\n')) >= 6]).rstrip('\n')
C'est très simple:
grep ...... inputfile > resultfile #There are 6 dots
Ceci est extrêmement efficace, car grep
ne cherchera pas à analyser plus que nécessaire, ni à interpréter les caractères de quelque manière que ce soit: il envoie simplement une ligne (entière) à stdout (que le shell redirige ensuite vers resultfile) comme sitôt que il a vu 6 caractères sur cette ligne (.
dans un contexte d’expression rationnelle correspond à un caractère quelconque).
Donc, grep ne sortira que les lignes ayant 6 (ou plus) caractères, et les autres ne sont pas sorties par grep, elles ne le feront donc pas dans resultfile.
Méthode la plus rapide: compilez et exécutez ce programme C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFFER_SIZE 1000000
int main(int argc, char *argv[]) {
int length;
if(argc == 3)
length = atoi(argv[2]);
else
return 1;
FILE *file = fopen(argv[1], "r");
if(file != NULL) {
char line[MAX_BUFFER_SIZE];
while(fgets(line, sizeof line, file) != NULL) {
char *pos;
if((pos = strchr(line, '\n')) != NULL)
*pos = '\0';
if(strlen(line) >= length)
printf("%s\n", line);
}
fclose(file);
}
else {
perror(argv[1]);
return 1;
}
return 0;
}
Compilez avec gcc program.c -o program
, exécutez avec ./program file line_length
(où file
= chemin du fichier et line_length
= longueur minimale de la ligne, dans votre cas 6
; la longueur maximale est limitée à 1000000
caractères par ligne; vous pouvez modifier cette valeur en modifiant la valeur de MAX_BUFFER_SIZE
). .
(Astuce pour remplacer \n
par \0
trouvé ici .)
Comparaison avec toutes les autres solutions proposées à cette question, à l’exception de la solution Shell (test exécuté sur un fichier de ~ 91Mo contenant 10 millions de lignes et une longueur moyenne de 8 caractères):
time ./foo file 6
real 0m1.592s
user 0m0.712s
sys 0m0.160s
time grep ...... file
real 0m1.945s
user 0m0.912s
sys 0m0.176s
time grep -E '^.{6,}$'
real 0m2.178s
user 0m1.124s
sys 0m0.152s
time awk 'length>=6' file
real 0m2.261s
user 0m1.228s
sys 0m0.160s
time Perl -lne 'length>=6&&print' file
real 0m4.252s
user 0m3.220s
sys 0m0.164s
sed -r '/^.{,5}$/d' file >out
real 0m7.947s
user 0m7.064s
sys 0m0.120s
./script.py >out
real 0m8.154s
user 0m7.184s
sys 0m0.164s
awk 'length>=6' file
length>=6
: si length>=6
renvoie VRAI, imprime l'enregistrement en cours.Perl -lne 'length>=6&&print' file
lenght>=6
renvoie TRUE, imprime l'enregistrement en cours.% cat file
a
bb
ccc
dddd
eeeee
ffffff
ggggggg
% ./foo file 6
ffffff
ggggggg
% awk 'length>=6' file
ffffff
ggggggg
% Perl -lne 'length>=6&&print' file
ffffff
ggggggg
Vous pouvez utiliser Vim en mode Ex:
ex -sc 'v/\v.{6}/d' -cx file
\v
activer la magie
.{6}
trouver des lignes de 6 caractères ou plus
v
invertir la sélection
d
delete
x
save and close
Solution de rubis:
$ cat input.txt
abcdef
abc
abcdefghijk
$ Ruby -ne 'puts $_ if $_.chomp.length() >= 6 ' < input.txt
abcdef
abcdefghijk
Idée simple: redirigez le fichier dans le stdin de Ruby et imprimez la ligne à partir de stdin uniquement si sa longueur est supérieure ou égale à 6