J'ai un dossier f1
:
line1
line2
line3
line4
..
..
Je veux supprimer toutes les lignes qui sont dans un autre fichier f2
:
line2
line8
..
..
J'ai essayé quelque chose avec cat
et sed
, qui n'était même pas proche de ce que je voulais. Comment puis-je faire ceci?
Réponses:
grep -v -x -f f2 f1
devrait faire l'affaire.Explication:
-v
pour sélectionner des lignes non correspondantes-x
pour correspondre uniquement aux lignes entières-f f2
pour obtenir des modèles def2
On peut à la place utiliser
grep -F
oufgrep
faire correspondre des chaînes fixes à partir def2
plutôt que des modèles (au cas où vous voudriez supprimer les lignes d'une manière "ce que vous voyez si ce que vous obtenez" plutôt que de traiter les lignesf2
comme des modèles regex).la source
grep
. S'il effectue un prétraitementf2
correct avant de commencer la recherche, la recherche ne prendra que O (n) temps.Essayez plutôt comm (en supposant que f1 et f2 sont «déjà triés»)
la source
comm
la solution soit la question n'indique pas que les lignesf1
sont triées, ce qui est une condition préalable à l'utilisationcomm
comm -2 -3 <(sort f1) <(sort f2)
Pour exclure les fichiers qui ne sont pas trop volumineux, vous pouvez utiliser les tableaux associatifs d'AWK.
La sortie sera dans le même ordre que le fichier "from-this.txt". La
tolower()
fonction le rend insensible à la casse, si vous en avez besoin.La complexité algorithmique sera probablement O (n) (taille exclude-these.txt) + O (n) (taille from-this.txt)
la source
exclude-these.txt
est vide. La réponse de @ jona-christopher-sahnwaldt ci-dessous fonctionne dans ce cas. Vous pouvez également spécifier plusieurs fichiers, par exempleawk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 done.out failed.out f=2 all-files.out
Similaire à la réponse de Dennis Williamson (principalement des changements syntaxiques, par exemple en définissant explicitement le numéro de fichier au lieu de l'
NR == FNR
astuce):awk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 exclude-these.txt f=2 from-this.txt
L'accès
r[$0]
crée l'entrée pour cette ligne, pas besoin de définir une valeur.En supposant que awk utilise une table de hachage avec une recherche constante et un temps de mise à jour constant (en moyenne), la complexité temporelle de celle-ci sera O (n + m), où n et m sont les longueurs des fichiers. Dans mon cas, n était ~ 25 millions et m ~ 14000. La solution awk était beaucoup plus rapide que le tri, et j'ai également préféré conserver l'ordre d'origine.
la source
f
plus claire queNR == FNR
, mais c'est une question de goût. L'affectation dans le hachage doit être si rapide qu'il n'y a pas de différence de vitesse mesurable entre les deux versions. Je pense que je me suis trompé sur la complexité - si la recherche est constante, la mise à jour doit également être constante (en moyenne). Je ne sais pas pourquoi je pensais que la mise à jour serait logarithmique. Je modifierai ma réponse.awk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 empty.file done.out failed.out f=2 all-files.out
. Alors que l'autreawk
solution échoue avec un fichier d'exclusion vide et ne peut en prendre qu'un.si vous avez Ruby (1.9+)
Qui a une complexité O (N ^ 2). Si vous voulez vous soucier des performances, voici une autre version
qui utilise un hachage pour effectuer la soustraction, de même que la complexité O (n) (taille de a) + O (n) (taille de b)
voici une petite référence, gracieuseté de user576875, mais avec 100K lignes, de ce qui précède:
diff
a été utilisé pour montrer qu'il n'y a aucune différence entre les 2 fichiers générés.la source
Quelques comparaisons temporelles entre diverses autres réponses:
sort f1 f2 | uniq -u
n'est même pas une différence symétrique, car elle supprime les lignes qui apparaissent plusieurs fois dans l'un ou l'autre fichier.comm peut également être utilisé avec stdin et ici des chaînes:
la source
Semble être un travail adapté au shell SQLite:
la source
Avez-vous essayé cela avec sed?
la source
Pas une réponse de «programmation» mais voici une solution rapide et sale: il suffit d'aller sur http://www.listdiff.com/compare-2-lists-difference-tool .
Évidemment, cela ne fonctionnera pas pour des fichiers volumineux, mais cela a fait l'affaire pour moi. Quelques notes:
la source