J'utilise Solaris 10 et donc les options grep impliquant -f ne fonctionnent pas.
J'ai deux fichiers séparés par des tubes :
fichier1 :
abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|
fichier 2 :
abc|123|
kumar|pki|
cab|234
Je voudrais comparer les deux premières colonnes de file2 avec file1 (recherche dans tout le contenu de file1 dans les deux premières colonnes) si elles correspondent à la ligne correspondante de file1. Recherchez ensuite la deuxième ligne du fichier 2 et ainsi de suite.
Sortie attendue :
abc|123|BNY|apple|
cab|234|cyx|orange|
Les fichiers que j'ai sont énormes, contenant environ 400 000 lignes, donc je voudrais rendre l'exécution rapide.
Réponse acceptée :
C'est pour cela qu'awk a été conçu :
$ awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file2 file1
abc|123|BNY|apple|
cab|234|cyx|orange|
Explication
-F'|'
:définit le séparateur de champs sur|
.NR==FNR
:NR est le numéro de ligne d'entrée courant et FNR le numéro de ligne du fichier courant. Les deux ne seront égaux que pendant la lecture du 1er fichier.-
c[$1$2]++; next
:s'il s'agit du 1er fichier, enregistrez les deux premiers champs dans lec
déployer. Ensuite, passez à la ligne suivante pour que cela ne soit appliqué que sur le 1er fichier. -
c[$1$2]>0
:le bloc else ne sera exécuté que si c'est le deuxième fichier donc on vérifie si les champs 1 et 2 de ce fichier ont déjà été vus (c[$1$2]>0
) et s'ils l'ont été, nous imprimons la ligne. Dansawk
, l'action par défaut est d'imprimer la ligne donc sic[$1$2]>0
est vrai, la ligne sera imprimée.
Alternativement, puisque vous avez tagué avec Perl :
perl -e 'open(A, "file2"); while(<A>){/.+?|[^|]+/ && $k{$&}++};
while(<>){/.+?|[^|]+/ && do{print if defined($k{$&})}}' file1
Explication
La première ligne ouvrira file2
, tout lire jusqu'au 2ème |
(.+?|[^|]+
) et enregistrez-le (le $&
est le résultat du dernier opérateur de correspondance) dans le %k
hachage.
La deuxième ligne traite file1, utilise la même regex pour extraire les deux premières colonnes et imprimer la ligne si ces colonnes sont définies dans le %k
hachage.
Les deux approches ci-dessus devront contenir les 2 premières colonnes de file2 en mémoire. Cela ne devrait pas poser de problème si vous n'avez que quelques centaines de milliers de lignes, mais si c'est le cas, vous pouvez faire quelque chose comme
cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done
Mais ce sera plus lent.
Connexe :Copiez tous les programmes et fichiers installés sur un disque dur (avec Windows 7 32 bits) et clonez-le/transférez-le sur un autre ordinateur avec Windows 7 64 bits ?