web-dev-qa-db-fra.com

Comment puis-je supprimer toutes les lignes d'un fichier de moins de 6 caractères?

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?

17
TellMeWhy

Il y a plusieurs façons de le faire.

Utilisation de grepname__:

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 sedname__, 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 grepou éditer le fichier sur place à l'aide de l'option -i de sedname__:

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 pythonname __, même plus lent que grepname__, sedname__:

#!/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')
30
heemayl

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.

19
Olivier Dulac

Solution n ° 1: utiliser C

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

Solution n ° 2: en utilisant AWK:

awk 'length>=6' file
  • length>=6: si length>=6 renvoie VRAI, imprime l'enregistrement en cours.

Solution n ° 3: utiliser Perl:

Perl -lne 'length>=6&&print' file
  • Si 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
14
kos

Vous pouvez utiliser Vim en mode Ex:

ex -sc 'v/\v.{6}/d' -cx file
  1. \v activer la magie

  2. .{6} trouver des lignes de 6 caractères ou plus

  3. vinvertir la sélection

  4. ddelete

  5. xsave and close

2
Steven Penny

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

1