Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2158 connectés 

  FORUM HardWare.fr
  Linux et OS Alternatifs
  Codes et scripts

  BASH : Comparer 2 fichiers et afficher les similarités

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

BASH : Comparer 2 fichiers et afficher les similarités

n°1373112
barbanegra
Posté le 04-02-2015 à 09:26:18  profilanswer
 

Bonjour, je débute en BASH et dois réaliser une opération à l'aide d'un script.
Le problème étant le suivant :  
J'ai 2 fichiers "queue -p" d'un serveur de mail (file d'attente des mails),  je dois comparer 2 de ces fichiers (enregistrés avec quelques minutes de décalage) afin de relever les mails qui n'arrivent pas à partir.
J'ai eu le raisonnement suivant : Je lis le premier fichier, et, ligne par ligne je le compare à toutes les lignes du second fichier et j'envoie les lignes similaires dans un autre fichier appelé "same.txt". J'ai réalisé ce script :
 

Code :
  1. fichier1="/home/pedro/Bureau/Pierre/pq1.txt"
  2. fichier2="/home/pedro/Bureau/Pierre/pq2.txt"
  3. while read line < $fichier1
  4. do
  5.         read enil < $fichier2
  6.         if [ "$line" = "$enil" ]
  7.         then
  8.                 echo $line > same.txt
  9.         fi
  10. done


 
Cependant lorsque j'exécute ce code, seule la première ligne (qui est la même dans les deux fichiers) est affichée en boucle.
Pourriez-vous m'orienter ?


Message édité par black_lord le 04-02-2015 à 11:19:06
mood
Publicité
Posté le 04-02-2015 à 09:26:18  profilanswer
 

n°1373133
black_lord
Modérateur
Truth speaks from peacefulness
Posté le 04-02-2015 à 11:18:24  profilanswer
 

sinon tu as l'utilitaire "comm", qui est l'inverse de "diff"


---------------
uptime is for lousy system administrators what Viagra is for impotent people - mes unixeries - github me
n°1375649
netmonk
Posté le 13-04-2015 à 15:40:41  profilanswer
 

il te faut une deuxième boucle pour itérer toutes les lignes du second fichier.  
 
Pour l'instant tu itères sur toutes les lignes du premier fichier que tu compares a la première ligne du second fichier (second read).  
Donc seul la première ligne du premier fichier matche à priori.  
 
Tu as donc besoin d'une deuxième boucle while read do pour itérer les lignes de ton second fichier.  
 
 

n°1375659
Profil sup​primé
Posté le 13-04-2015 à 22:03:50  answer
 

salut,
 
d'une part, le script original est faux : la boucle ne finira jamais, car read lit la première ligne du fichier.
le fichier doit être versé dans la boucle while :

Code :
  1. while read -r line; do echo "$line"; done <fichier


 
la suggestion de netmonk ne fonctionnera pas, parce que la deuxième boucle lira le flux dans lequel est versé le fichier.
il faut utiliser des descripteurs de fichier.
à condition que les fichiers ont le même nombre de lignes ceci devrait fonctionner (je te laisse faire la comparaison) :

Code :
  1. exec {desc1}<fichier1
  2. exec {desc2}<fichier2
  3. while read -ru $desc1 line1
  4. do
  5.    read -ru $desc2 line2
  6.    echo "$line1 ?= $line2"
  7. done

n°1375663
o'gure
Modérateur
Multi grognon de B_L
Posté le 14-04-2015 à 00:21:03  profilanswer
 

La réponse de blacklord  n est pas satisfaisante ?

black_lord a écrit :

sinon tu as l'utilitaire "comm", qui est l'inverse de "diff"



---------------
Relax. Take a deep breath !
n°1375667
Profil sup​primé
Posté le 14-04-2015 à 10:53:48  answer
 

OOPS

Citation :

la suggestion de netmonk ne fonctionnera pas, parce que la deuxième boucle lira le flux dans lequel est versé le fichier.

:sweat:
ce n'est pas ça non plus : j'ai confondu avec la lecture depuis stdin, qui ne fonctionne pas lors de la lecture d'un fichier.  :(
 
 
par contre, après test (de l'importance de tester les codes !!!), la suggestion de netmonk ne fonctionnera quand même pas, car pour chaque ligne du fichier #1, le fichier #2 sera lu entièrement.
 
vu qu'il est question de relever «les lignes similaires», comm est sans doute une meilleure alternative.

n°1375668
black_lord
Modérateur
Truth speaks from peacefulness
Posté le 14-04-2015 à 11:15:59  profilanswer
 

o'gure a écrit :

La réponse de blacklord  n est pas satisfaisante ?


 
c'est trop efficace :o


---------------
uptime is for lousy system administrators what Viagra is for impotent people - mes unixeries - github me
n°1375670
netmonk
Posté le 14-04-2015 à 12:09:10  profilanswer
 

hum un algo basique et brute force consistant à trouver les lignes identiques dans deux fichiers je pense que deux boucles while do imbriquées qui comparent chaques lignes du premier fichier avec toutes les lignes du deuxieme fichier est plutot satisfaisant.  
 
Tu peux rajouter un break dans le while imbriqué pour sortir directement de celui-ci dés que tu trouves une ligne qui match.  
 
C'est juste que là j'ai pas la main sur une console, mais ce soir je sors un bout de code qui fonctionne.  
 
Cependant je suis d'accord pour utiliser comm commande native sera de facto beaucoup plus efficace.


Message édité par netmonk le 14-04-2015 à 13:34:28
n°1375681
netmonk
Posté le 14-04-2015 à 14:37:32  profilanswer
 

[0]$ cat test1
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
0 0
[0]$ cat test2
1 1
3 3
9 9
5 5
9 9
10 10
[0]$ cat comp
while read line1; do
        while read line2; do
                if [ "$line2" = "$line1" ]
                then
                        echo $line1
                        break
                fi
        done < test2
done < test1
[0]$ bash comp
1 1
3 3
5 5
9 9


Message édité par netmonk le 14-04-2015 à 14:58:07
n°1375698
Profil sup​primé
Posté le 14-04-2015 à 18:24:47  answer
 

ça n'enlève rien à ce que j'ai dit.
si on retire le test (ou si on met un set -x), on voit tout de suite ce que je voulais vous faire éviter :

Code :
  1. $ cat test1
  2. 1 1
  3. 2 2
  4. 3 3
  5. 4 4
  6. 5 5
  7. 6 6
  8. 7 7
  9. 8 8
  10. 9 9
  11. 0 0
  12. $ cat test2
  13. 1 1
  14. 3 3
  15. 9 9
  16. 5 5
  17. 9 9
  18. 10 10
  19. $ while read line1; do while read line2; do echo "$line2" = "$line1"; done < test2; done < test1
  20. 1 1 = 1 1
  21. 3 3 = 1 1
  22. 9 9 = 1 1
  23. 5 5 = 1 1
  24. 9 9 = 1 1
  25. 10 10 = 1 1
  26. 1 1 = 2 2
  27. 3 3 = 2 2
  28. 9 9 = 2 2
  29. 5 5 = 2 2
  30. 9 9 = 2 2
  31. 10 10 = 2 2
  32. 1 1 = 3 3
  33. 3 3 = 3 3
  34. 9 9 = 3 3
  35. 5 5 = 3 3
  36. 9 9 = 3 3
  37. 10 10 = 3 3
  38. 1 1 = 4 4
  39. 3 3 = 4 4
  40. 9 9 = 4 4
  41. 5 5 = 4 4
  42. 9 9 = 4 4
  43. 10 10 = 4 4
  44. 1 1 = 5 5
  45. 3 3 = 5 5
  46. 9 9 = 5 5
  47. 5 5 = 5 5
  48. 9 9 = 5 5
  49. 10 10 = 5 5
  50. 1 1 = 6 6
  51. 3 3 = 6 6
  52. 9 9 = 6 6
  53. 5 5 = 6 6
  54. 9 9 = 6 6
  55. 10 10 = 6 6
  56. 1 1 = 7 7
  57. 3 3 = 7 7
  58. 9 9 = 7 7
  59. 5 5 = 7 7
  60. 9 9 = 7 7
  61. 10 10 = 7 7
  62. 1 1 = 8 8
  63. 3 3 = 8 8
  64. 9 9 = 8 8
  65. 5 5 = 8 8
  66. 9 9 = 8 8
  67. 10 10 = 8 8
  68. 1 1 = 9 9
  69. 3 3 = 9 9
  70. 9 9 = 9 9
  71. 5 5 = 9 9
  72. 9 9 = 9 9
  73. 10 10 = 9 9
  74. 1 1 = 0 0
  75. 3 3 = 0 0
  76. 9 9 = 0 0
  77. 5 5 = 0 0
  78. 9 9 = 0 0
  79. 10 10 = 0 0

ce n'est pas du tout satisfaisant.

mood
Publicité
Posté le 14-04-2015 à 18:24:47  profilanswer
 

n°1375704
netmonk
Posté le 14-04-2015 à 21:13:18  profilanswer
 

Forcement tu fais une combinaison de toutes les lignes du premier fichier avec toutes les lignes du second fichier.  
 
Mon code est un peu plus optimisé puisque on sort du while imbriqué dès que l'on trouve un match.  
 
Cependant je ne comprend en rien tes histoires de descripteur de fichier. Tu as une page de manuel ou un lien vers de la doc ?

n°1375705
Fork Bomb
Obsédé textuel
Posté le 14-04-2015 à 21:17:48  profilanswer
 

sinon tu as l'utilitaire "comm", qui est l'inverse de "diff"


---------------
Décentralisons Internet-Bépo-Troll Bingo - "Pour adoucir le mélange, pressez trois quartiers d’orange !"
n°1375706
netmonk
Posté le 14-04-2015 à 21:31:25  profilanswer
 

Et d'un point de vue purement algorithmique je ne suis pas sûr que "comm" fasse vraiment mieux :)

n°1375709
Profil sup​primé
Posté le 14-04-2015 à 21:56:16  answer
 

tu vas trouver des explications à propos des descripteurs de fichiers dans l'ABS.
quand une ligne d'un descripteur de fichier est lue, elle est retirée de ce dernier.
 
de manière POSIX, on ferait ainsi :

Code :
  1. while read -r line <&4
  2. do
  3.    read -r line2 <&5
  4.    echo "$line -- $line2"
  5. done 4<test1 5<test2
  6. 1 1 -- 1 1
  7. 2 2 -- 3 3
  8. 3 3 -- 9 9
  9. 4 4 -- 5 5
  10. 5 5 -- 9 9
  11. 6 6 -- 10 10
  12. 7 7 --
  13. 8 8 --
  14. 9 9 --
  15. 0 0 --

parce que POSIX read n'a pas d'option -u pour lire les df.
on pourrait aussi passer les fichier dans un df en utilisant exec.
 
il y a quand même plus de chances que comm fonctionne de cette façon.
les langages un peu plus bas niveau que le shell, comme perl, python, php, ouvrent un fichier dans un descripteur de fichier, puis parcourent ce descripteur de fichier.


Message édité par Profil supprimé le 14-04-2015 à 22:03:24
n°1375710
netmonk
Posté le 14-04-2015 à 22:51:08  profilanswer
 

Watael : dernière question: en quoi ton bout de code fait ce que demande le post initial ?  
C'est bien beau de m'empapaouter avec tes filesdesc mais moi je vois que ton résultat ne correspond en rien au problème initiale.
 
Merci donc de fournir un code qui réponde au problème initial et qui de surcroît spécifie à tes remarques.


Message édité par netmonk le 14-04-2015 à 22:52:45
n°1375711
Profil sup​primé
Posté le 14-04-2015 à 23:08:02  answer
 

le problème de barbanegra était de lire deux fichiers dans une seul boucle while :

Citation :

Cependant lorsque j'exécute ce code, seule la première ligne (qui est la même dans les deux fichiers) est affichée en boucle.
Pourriez-vous m'orienter ?

s'il veut faire ça en shell, la meilleure solution est d'utiliser des df, et pas d'ouvrir autant de fois un fichier qu'il y a de lignes dans l'autre !

n°1375712
netmonk
Posté le 14-04-2015 à 23:14:37  profilanswer
 


 
Tu me trolles méchamment là l'ami, je cite :  

Citation :

J'ai 2 fichiers "queue -p" d'un serveur de mail (file d'attente des mails),  je dois comparer 2 de ces fichiers (enregistrés avec quelques minutes de décalage) afin de relever les mails qui n'arrivent pas à partir.  
J'ai eu le raisonnement suivant : Je lis le premier fichier, et, ligne par ligne je le compare à toutes les lignes du second fichier et j'envoie les lignes similaires dans un autre fichier appelé "same.txt". J'ai réalisé ce script :


 
Voilà! ce n'est pas parce que barbanegra n'a pas réussi a coder ce qu'il voulait réellement faire (incompréhension de l'utilisation de read) que son besoin n'est pas exprimé clairement.
Et c'est d'ailleurs ce que je dis dans mon premier post: son code ne correspond en rien à ce qu'il cherche à faire : identifier toutes les lignes du fichier 1 qui sont présentes dans le fichier 2 (et réciproquement) ou de manière plus logique faire une intersection du fichier1 et du fichier2.  
 
Et ni ton code ni le sien ne répondent à ce problème.  
 
Maintenant je ne suis pas dans le cerveau de barbe-noire, donc il existe une marge d'erreur.
 
Enfin j'ai utilisé tes fameux FD :

while read -r line1 <&9 ; do  
        while read -r line2 <&10; do  
                if [ "$line2" = "$line1" ]  
                then  
                        echo $line1  
                        break  
                fi  
        done 10< test2  
done 9< test1  


Ce qui me donne exactement la même sortie de bash -x que sans les redirections FD.  


Message édité par netmonk le 14-04-2015 à 23:18:10
n°1375713
netmonk
Posté le 14-04-2015 à 23:21:20  profilanswer
 

Sinon il y a grep aussi :  

plonky@netmonk ~ $ grep  -f test1 test2 |sort|uniq
1 1  
3 3  
5 5  
9 9


 
comm n'a pas l'air efficace :

plonky@netmonk ~ $ comm -12 test1 test2
1 1  
3 3  
9 9  
comm: le fichier 1 n'est pas dans l'ordre attendu
comm: le fichier 2 n'est pas dans l'ordre attendu


 
Et un petit bug dans comm :  

plonky@netmonk ~ $ comm -12 --nocheck-order test1 test2
1 1  
3 3  
9 9  


Il n'affiche pas "5 5" qui est commun aux deux fichiers.  


Message édité par netmonk le 14-04-2015 à 23:26:01
n°1375714
netmonk
Posté le 14-04-2015 à 23:38:33  profilanswer
 

'The infamous "Advanced" Bash Scripting Guide should be avoided unless you know how to filter out the junk. It will teach you to write bugs, not scripts. In that light, the BashGuide was written: http://mywiki.wooledge.org/BashGuide'
 
#bash@freenode

n°1375716
Profil sup​primé
Posté le 14-04-2015 à 23:47:49  answer
 

Citation :

Ce qui me donne exactement la même sortie de bash -x que sans les redirections FD.  

normal, puisque tu génères un fd pour chaque ligne du premier fichier; les fd sont utiles parce qu'ils sont lus une seule fois.
 
comm ne convient pas non plus, alors, puisqu'il lit les deux fichiers ligne par ligne (ligne1.fichier1 ligne1.fichier2, etc).

Citation :

Forcing `comm' to process wrongly sorted input files containing
unpairable lines by specifying `--nocheck-order' is not guaranteed to
produce any particular output.  The output will probably not correspond
with whatever you hoped it would be.

3 3 ne devrait pas apparaître puisqu'ils ne sont pas sur la même ligne. :(
 
je plussoie la solution grep, pour faire ce que tu as compris.

n°1375718
netmonk
Posté le 14-04-2015 à 23:53:58  profilanswer
 

Pour enterrer la hache de guerre : http://mywiki.wooledge.org/BashFAQ/036
 
J'avais oublié le coup du uniq -d :

plonky@netmonk ~ $ sort test1 test2|uniq -d  
1 1  
3 3  
5 5  
9 9  


Message édité par netmonk le 14-04-2015 à 23:56:25
mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Linux et OS Alternatifs
  Codes et scripts

  BASH : Comparer 2 fichiers et afficher les similarités

 

Sujets relatifs
Script Bash (débutant) - manipulations chaines de charactéres ?[CentOs/Nginx] visionnage de fichiers uploadés : 403 forbidden
Problème paramètre sortie procédure script bashPuissance 4 Bash
Faire une recherche sur un liste de noms de fichiersProgramme en ligne de commande sans afficher les erreurs
Samba : impossible d'exécuter des fichiers distants[Bash - Shell] Script qui se lance tant que la condition est pas valid
Impossible d'afficher en 2560 x 1440débutant bash : script de déplacement fichiers/dossiers
Plus de sujets relatifs à : BASH : Comparer 2 fichiers et afficher les similarités


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR