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
.
!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
.