Supprimer les observations du fichier texte en fonction des valeurs répertoriées dans un fichier séparé

J’ai un fichier texte d’environ 15 000 000 lignes (fichier A) avec les colonnes suivantes:

1 1:693731 0 693731 GA 1 1:706992 0 706992 TC 1 1:707014 0 707014 CA 1 1:715142 0 715142 TG 1 1:724721 0 724721 AC 1 1:729679 0 729679 CG ... 

Dans un fichier séparé (fichier B), j’ai une liste d’environ 80 000 observations que je souhaite supprimer du fichier A:

 1:706992 1:715142 1:729679 ... 

Je souhaite supprimer des lignes du fichier A en fonction de la valeur de la colonne 2 (répertoriée dans le fichier B) et imprimer la sortie. Ainsi, le fichier de sortie devrait ressembler à ceci:

 1 1:693731 0 693731 GA 1 1:707014 0 707014 CA 1 1:724721 0 724721 AC 

Toute consortingbution serait vivement appréciée.

Une solution awk un seul passage:

 awk 'NR==FNR { xclude[$0]++; next } !xclude[$2]' fileB fileA 
  • NR==FNR { xclude[$0]++; next } NR==FNR { xclude[$0]++; next } traite uniquement les lignes du 1er fichier d’entrée ( fileB ) et stocke ses lignes ( $0 ) en tant que clés du tableau associatif xclude avec des valeurs non nulles associées (en vertu de ++ ).

    • NR (l’indice de ligne global) est uniquement égal à FNR (l’index de ligne spécifique au fichier d’entrée) pour le premier fichier d’entrée; next ignore le rest du script et passe à la ligne d’entrée suivante.
  • !xclude[$2] n’est donc évalué que pour les lignes du 2ème fichier d’entrée ( fileA ) et n’imprime que les lignes dont la valeur de la deuxième colonne ( $2 ) n’est pas ( ! ) contenue dans le tableau des exclusions, xclude .

    • Notez que pattern !xclude[$2] évalue à true imprime implicitement la ligne en question, car il s’agit de l’action par défaut d’Awk en l’absence d’une action associée ( {...} ).

Dans un commentaire, Karakfa suggère la variante suivante, qui évite le besoin de ++ :

 awk 'NR==FNR { xclude[$0]; next } !($2 in xclude)' fileB fileA 
  • Le simple fait de référencer un élément de tableau amène Awk à le créer implicitement , donc xclude[$0] , bien qu’il xclude[$0] pas de valeur , crée un élément dont la clé est la valeur de $0 .

  • $2 in xclude alors simplement l’ existence de la clé $2 dans le tableau xclude avec l’opérateur xclude (sans tester la valeur , qui serait vide dans ce cas).

Avec grep:

 $ grep -vwFf fileB fileA 1 1:693731 0 693731 GA 1 1:707014 0 707014 CA 1 1:724721 0 724721 AC 

Avec ces options:

  • -v correspondance inversée: exclut les lignes qui correspondent
  • -w mot correspondant: ne correspond qu’à des mots entiers pour éviter la correspondance de sous-chaîne
  • -F chaînes fixes: n’interprète pas les chaînes de recherche comme des expressions rationnelles
  • -f read from file: utilise fileB comme liste de chaînes à rechercher

Plus verbeux, meilleur pour la lisibilité:

 grep --invert-match --word-regexp --fixed-ssortingngs --file=fileB fileA 

Notez que ce n’est pas une solution généralement applicable, mais pourrait fonctionner pour ce jeu de données, en supposant que la deuxième colonne est toujours la seule à contenir un deux-points.

si le fichier est sortingé dans la clé comme dans l’échantillon, vous pouvez utiliser la jointure

 $ join -v1 -12 file1 file2 | awk -v OFS='\t' '{t=$2;$2=$1;$1=t}1' 1 1:693731 0 693731 GA 1 1:707014 0 707014 CA 1 1:724721 0 724721 AC 

Vous pouvez également effectuer le classement des colonnes avec l’option -o .