Comparez deux fichiers avec la première colonne et supprimez la ligne en double du 2e fichier dans le script shell


9

Je vais poser ma question avec un exemple. J'ai 2 fichiers:

Fichier # 1:

118D FC300_R5_TP  FX.B      32775       2112   6       2038   6       2112   0
118E FC300_R5_TP  FX.B      32775       2136   7       2065   6       2136   0
118F FC300_R5_TP  FX.B      32775       2124   6       2064   6       2124   0
1190 FC300_R5_TP  FX.B     819210     814632  99     814609  99     814632   0
1191 FC300_R5_TP  FX.B     819210     104100  13     103714  13     104100   0
1192 FC300_R5_TP  FX.B    1638420    1609476  98    1609402  98    1609476   0
1196 FC300_R5_TP  FX.B    1638420    1638432 100    1638379 100    1638432   0
119A FC300_R5_TP  FX.B    3276840    3271776 100    3271698 100    3271776   0
119E FC300_R5_TP  FX.B    3276840    3264120 100    3264034 100    3264120   0
11A2 FC300_R5_TP  FX.B    3276840    2328648  71    2328546  71    2328648   0
11A6 FC300_R5_TP  FX.B    3276840    2328444  71    2328355  71    2328444   0
11AA FC300_R5_TP  FX.B    3276840    2328528  71    2328403  71    2328528   0
11AE FC300_R5_TP  FX.B    3276840    2328648  71    2328468  71    2328648   0
11B2 FC300_R5_TP  FX.B    3276840    2130000  65    2129766  65    2130000   0
173A FC300_R5_TP  FX.B    6553680    6478572  99    6477747  99    6478572   0

Fichier # 2:

11AA FC300_R5_TP  FX.B    3276840    2328528  71    2328403  71    2328528   0
11AE FC300_R5_TP  FX.B    3276840    2328648  71    2328468  71    2328648   0
11B2 FC300_R5_TP  FX.B    3276840    2130000  65    2129766  65    2130000   0
173A FC300_R5_TP  FX.B    6553680    6478572  99    6477747  99    6478572   0
0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Sortie désirée

Fichier # 3:

0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Je voudrais comparer le fichier 1 et le fichier 2 en utilisant leurs premières colonnes et supprimer la ligne ou la ligne entière du fichier 2 où ils correspondent dans le fichier 1. Je voudrais également enregistrer les résultats dans un troisième fichier, le fichier # 3.

Réponses:


10

Vous pouvez utiliser awkpour cela:

awk 'FNR==NR{a[$1];next};!($1 in a)' file1 file2 > file3

Explication:

  • FNR == NR: Ce test est vrai lorsque le nombre d'enregistrements est égal au nombre d'enregistrements dans le fichier. Cela n'est vrai que pour le premier fichier, car le second fichier NRsera égal au nombre de lignes de fichier1 + FNR.

  • a[$1]: Créez un index d'élément de tableau du premier champ de file1.

  • next: passer à l'enregistrement suivant afin qu'aucun traitement supplémentaire ne soit effectué sur le fichier1.

  • !($1 in a): Vérifiez si le premier champ ($ 1) est présent dans le tableau, c'est-à-dire dans file1, et imprimez la ligne entière (dans file3).

Basé sur l'un des exemples du wiki #awk .


Réponse parfaite !!!
mtk

8
export LC_ALL=C
comm -13 <(sort f1) <(sort  f2)

Rapporterait les lignes qui ne sont que f2.

export LC_ALL=C
join -v2 <(sort f1) <(sort f2)

Indiquerait les lignes f2dont le premier champ est introuvable comme premier champ d'une ligne de f1.

(vous avez besoin d'un shell prenant en charge la substitution de processus comme ksh93, zshou bash).


2

Juste pour le plaisir, voici une solution en Perl:

#!/usr/bin/perl

# create names lookup table from first file
my %names;
while (<>) {
    (my $col1)= split / /, $_;
    $names{$col1} = 1;
    last if eof;
}

# scan second file
while (<>) {
    print if /^(\S+).*/ && not $names{$1};
}

Exemple

$ ./showdiffs.pl file1  file2
0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Détails

La solution Perl ci-dessus est composée de 2 boucles. La première boucle lit toutes les lignes depuis file1et crée un hachage, %namesoù chaque colonne que nous identifions est ajoutée.

$names{11AA} = 1;

La 2e whileboucle passe ensuite sur le 2e fichier, file2et la colonne 1 de chaque ligne est identifiée à l'aide de l'expression régulière:

^(\S+).*

Ce qui précède dit que depuis le début de la ligne, faites correspondre tout ce qui n'est pas un espace et enregistrez-le dans la variable temporaire $1. Il est sauvé en enroulant des parens autour. Le .*dit de faire correspondre tout le reste sur la ligne.

Le bit suivant de ces lignes indique de rechercher le bit de la colonne 1 que nous venons d'enregistrer $1dans le %nameshachage:

$names{$1}

S'il est présent là-bas, nous ne voulons pas l'imprimer. S'il n'est pas là, imprimez-le.


2

Méthode 1 # Bash

#!/usr/bin/env bash
file1=$1
file2=$2

[[ $# -ne 2 ]]  && { echo -e "\n\tUsage: \t$0 file1 file2\n"; exit 1; }

while read line
do

        if ! grep -q "${line%% .*}" $file1; then
                echo "${line}"
        fi

done < $file2

Méthode 2 # seulement Grep

grep -v "$(< file1)" file2

grep fonctionne, mais pas une garantie


1

Permet de l'obtenir comme

Fichier # 1: file1.txt

Fichier # 2: file2.txt

Exécutez ensuite le suivi sur le terminal

fgrep -vf test1.txt test2.txt > output.txt

output.txt contiendra les résultats souhaités.

Explication:

fgrep : print lines matching a pattern (from manual page)
-v  : get only non-matching rows
-f : obtain PATTERN from FILE (from manual page)

Cela ne fonctionne que si des lignes entières sont identiques, mais l'interrogateur a explicitement demandé une comparaison uniquement dans la première colonne.
Adaephon
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.