Forum général.général Différences entre 2 listes de fichiers

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
4
4
août
2020

Bonjour,

J'ai 2 fichiers textes contenant chacun une liste de 120.000 chemins+fichiers sous la forme
/chemin/chemin/fichier1
/chemin/chemin/fichier2
/chemin/autre/fichier.truc

Je voudrais obtenir la liste des fichiers absents d'une des listes par rapport à l'autre, mais je n'y arrive pas. J'ai trié les listes par ordre alphabétique puis essayé des trucs mais sans succès. Je suis sur que c'est simple mais vraiment je crois que j'ai les neurones en compote. Je sens que je vais avoir honte tellement la solution est simple.

Il y a 7.000 fichiers qui manquent d'un côté ou de l'autre. Je veux uniquement ce qui manque d'un seul côté. Disons que j'ai une liste AVANT et une liste APRES. Je veux ce qui manque dans APRES sans me soucier de ce qui manque dans AVANT.

  • # diff

    Posté par  . Évalué à 1.

    diff a des options pour ca

    man diff pour trouver quelle option fait quoi

    • [^] # Re: diff

      Posté par  . Évalué à 1.

      Je n'ai rien trouvé qui fonctionne avec diff.
      Au mieux il y a l'option --suppress-common-lines mais ça ne donne pas ce que je recherche.

      • [^] # Re: diff

        Posté par  . Évalué à 2. Dernière modification le 04/08/20 à 16:34.

        neox@machine:Downloads % cat test1.txt
        /chemin/chemin/fichier1
        /chemin/chemin/fichier2
        /chemin/autre/fichier.truc
        neox@machine:Downloads % cat test2.txt
        /chemin/chemin/fichier1
        /chemin/chemin/fichier3
        /chemin/autre/fichier.truc
        neox@machine:Downloads % diff test1.txt test2.txt
        2c2
        < /chemin/chemin/fichier2
        ---
        > /chemin/chemin/fichier3

        diff me dit bien que /chemin/chemin/fichier2 est present dans le fichier1 mais pas dans le 2

        et /chemin/chemin/fichier3 est dans fichier2 mais pas dans le fichier1

        • [^] # Re: diff

          Posté par  . Évalué à 1.

          La question est "Je veux ce qui manque dans APRES sans me soucier de ce qui manque dans AVANT."

          Je peux ensuite faire un sed pour virer toutes les lignes genre "2c2" et "----" et "< ".
          Ca marche, mais tu as affirmé que sed a des options pour ça, c'est faux.

          J'ai trouvé plus efficace, je fais le message plus bas.

  • # comm

    Posté par  . Évalué à 6.

    La commande comm des coreutils permet d'opérer sur des fichiers triés :

    https://www.gnu.org/software/coreutils/manual/html_node/comm-invocation.html#comm-invocation

    • [^] # Re: comm

      Posté par  . Évalué à 2.

      Tellement simple, merci !

      J'ai fait comm -13 fichier1 fichier2 et ça fait exactement ce que je voulais.

  • # mc

    Posté par  . Évalué à 0. Dernière modification le 04/08/20 à 14:44.

    J'aime bien, avec GNU Midnight Commander,
    sélectionner les deux répertoires
    et juste avoir à faire Ctrl+X puis appuyer sur la touche D

    Le gros défaut de cet outil,
    c'est qu'on finit par oublier beaucoup de noms de commandes et leurs options.

  • # Comme dit l'adage

    Posté par  . Évalué à 1. Dernière modification le 04/08/20 à 15:18.

    Salut,

    There is more than one way to do it.

    A peu près tout langage sait faire ça. Plus ou moins optimisé. Mais pour quelques 100k de lignes, je ne m’inquiéterai pas.

    D'ailleurs, c'est un bon exercice !

    Matricule 23415

    • [^] # Re: Comme dit l'adage

      Posté par  (site Web personnel) . Évalué à 2.

      There is more than one way to do it.

      Oui, mais des fois c'est moins simple :

      #!/usr/bin/perl
      use strict;
      use warnings;
      use List::Compare;
      
      open (my $log, "<", "log") or die $!;
      open (my $master, "<", "master") or die $!;
      my @content_log=<$log>;
      my @content_master=<$master>;
      
      my $lc = List::Compare->new(\@content_log, \@content_master);    
      my @intersection = $lc->get_intersection;
      my @firstonly = $lc->get_unique;
      my @secondonly = $lc->get_complement;
      
      print "Common Items:\n"."@intersection"."\n";
      print "Items Only in First List:\n"."@firstonly"."\n";
      print "Items Only in Second List:\n"."@secondonly"."\n";
      
      print "log\n", $lc->get_unique,"\n"; 
      print "master\n", $lc->get_complement,"\n"; 
      
      close $log;
      close $master;

      source

      « Il vaut mieux mobiliser son intelligence sur des conneries que mobiliser sa connerie sur des choses intelligentes. »

      • [^] # Re: Comme dit l'adage

        Posté par  . Évalué à 2. Dernière modification le 04/08/20 à 16:00.

        Salut,

        je fais plus court avec mon exemple en R :)

        library(dplyr) # ça, c'est juste pour aller plus vite
        
        letters <-LETTERS # ici, on prend juste les majuscules
        missing <- letters[seq(1, length(letters), 2)] # ici on n'en prend qu'une sur deux, c'est juste pour l'exemple
        
        # et pis là...
        letters[letters %in% missing] # ah bin tiens, j'ai retrouvé toutes les lettres manquantes...

        Bon, c'est pas la taille qui compte, hein ;)

        Matricule 23415

        • [^] # Re: Comme dit l'adage

          Posté par  . Évalué à 2.

          Re salut,

          Et je peux aussi faire :

          `%not_in%` <- purrr::negate(`%in%`) # une petite fonction d'aide
          letters[letters %not_in% missing] # ah bin tiens, j'ai que le restant...

          (ouais, bon, je m'étais un peu gouré sur le post précédent mais pu éditer. Désolé pour les familles, toussa.)

          Matricule 23415

          • [^] # Re: Comme dit l'adage

            Posté par  (site Web personnel) . Évalué à 2.

            Bon, c'est pas la taille qui compte, hein ;)

            Toutafé :)

            « Il vaut mieux mobiliser son intelligence sur des conneries que mobiliser sa connerie sur des choses intelligentes. »

  • # Script python

    Posté par  . Évalué à 2.

    Salut,

    Perso, je ferais un script python :

    Je fais un set d'avant, un set d'après
    Je fais set(avant) - set (après)

    Je pense pas que ce soit le plus opti par contre, par contre c'est codable relativement rapidement.

    https://www.geeksforgeeks.org/python-set-difference/

    Bon courage !

  • # grep

    Posté par  . Évalué à 8.

    grep -vFxf fichier1 fichier2
    

    où fichier1 contient les lignes à exclure, et fichier2 la liste dans laquelle on cherche.

    • [^] # Re: grep

      Posté par  . Évalué à 1.

      Joli, merci !
      Je note l'astuce.

  • # sqlite

    Posté par  (site Web personnel) . Évalué à 3. Dernière modification le 05/08/20 à 14:22.

    $ echo chemin > liste1 && ls -1 / >> liste1
    $ echo chemin > liste2 && ls -1 /usr >> liste2
    $ sqlite3
    SQLite version 3.27.2 2019-02-25 16:06:06
    Enter ".help" for usage hints.
    Connected to a transient in-memory database.
    Use ".open FILENAME" to reopen on a persistent database.
    sqlite> .import liste1 table1
    sqlite> .import liste2 table2
    
    sqlite> .schema table1
    CREATE TABLE table1(
      "chemin" TEXT
    );
    sqlite> select * from table1 where chemin in (select * from table2);
    bin
    lib
    sbin
    sqlite> .output common
    sqlite> select * from table1 where chemin in (select * from table2);
    sqlite>
    $ cat common
    bin
    lib
    sbin

    Adhérer à l'April, ça vous tente ?

    • [^] # Re: sqlite

      Posté par  (site Web personnel) . Évalué à 3.

      En reformattant mon post pour présenter le code je me suis zoinxé le texte:

      Il y a peu j'ai utilisé sqlite avec succès pour faire des traitements complexes à partir de csv. J'aurais pu faire un script mais ça a l'avantage d'être près à l'emploi. Pour le coup c'est un peu un marteau pilon pour une mouche mais je le montre pour info.

      Adhérer à l'April, ça vous tente ?

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.