Vous pouvez y parvenir en contrôlant le formatage des anciennes / nouvelles / lignes inchangées dans la diffsortie GNU :
diff --new-line-format="" --unchanged-line-format="" file1 file2
Les fichiers d'entrée doivent être triés pour que cela fonctionne. Avec bash(et zsh), vous pouvez trier sur place avec la substitution de processus <( ):
diff --new-line-format="" --unchanged-line-format="" <(sort file1) <(sort file2)
Dans les lignes ci-dessus , les lignes nouvelles et inchangées sont supprimées, donc seules les lignes modifiées (c'est-à-dire les lignes supprimées dans votre cas) sont sorties. Vous pouvez également utiliser quelques diffoptions d' autres solutions n'offrent pas, comme -ipour ignorer la casse, ou diverses options (espaces blancs -E, -b, -vetc) pour la correspondance moins stricte.
Explication
Les options --new-line-format, --old-line-formatet --unchanged-line-formatvous permettent de contrôler la façon de diffformater les différences, comme pour les printfspécificateurs de format. Ces options mettent en forme respectivement les lignes nouvelles (ajoutées), anciennes (supprimées) et inchangées . Mettre un à vide "" empêche la sortie de ce type de ligne.
Si vous connaissez le format diff unifié , vous pouvez le recréer en partie avec:
diff --old-line-format="-%L" --unchanged-line-format=" %L" \
--new-line-format="+%L" file1 file2
Le %Lspécificateur est la ligne en question, et nous préfixons chacun avec "+" "-" ou "", comme diff -u
(notez qu'il ne produit que des différences, il manque les lignes --- +++et @@en haut de chaque changement groupé). Vous pouvez également l'utiliser pour faire d'autres choses utiles comme numéroter chaque ligne avec %dn.
La diffméthode (avec d'autres suggestions commet join) ne produit que la sortie attendue avec une entrée triée , bien que vous puissiez utiliser <(sort ...)pour trier sur place. Voici un awkscript simple (nawk) (inspiré des scripts liés dans la réponse de Konsolebox) qui accepte les fichiers d'entrée commandés arbitrairement et génère les lignes manquantes dans l'ordre dans lequel elles se produisent dans file1.
# output lines in file1 that are not in file2
BEGIN { FS="" } # preserve whitespace
(NR==FNR) { ll1[FNR]=$0; nl1=FNR; } # file1, index by lineno
(NR!=FNR) { ss2[$0]++; } # file2, index by string
END {
for (ll=1; ll<=nl1; ll++) if (!(ll1[ll] in ss2)) print ll1[ll]
}
Cela stocke le contenu entier de file1 ligne par ligne dans un tableau indexé de numéro de ligne ll1[], et le contenu entier de file2 ligne par ligne dans un tableau associatif indexé de contenu de ligne ss2[]. Une fois les deux fichiers lus, parcourez ll1et utilisez l' inopérateur pour déterminer si la ligne dans file1 est présente dans file2. (Cela aura une sortie différente de la diffméthode s'il y a des doublons.)
Dans le cas où les fichiers sont suffisamment volumineux pour que leur stockage entraîne un problème de mémoire, vous pouvez échanger la CPU contre de la mémoire en stockant uniquement file1 et en supprimant les correspondances en cours de lecture.
BEGIN { FS="" }
(NR==FNR) { # file1, index by lineno and string
ll1[FNR]=$0; ss1[$0]=FNR; nl1=FNR;
}
(NR!=FNR) { # file2
if ($0 in ss1) { delete ll1[ss1[$0]]; delete ss1[$0]; }
}
END {
for (ll=1; ll<=nl1; ll++) if (ll in ll1) print ll1[ll]
}
Ce qui précède stocke l'intégralité du contenu de file1 dans deux tableaux, l'un indexé par numéro de ligne ll1[], l'autre indexé par contenu de ligne ss1[]. Lorsque le fichier2 est lu, chaque ligne correspondante est supprimée de ll1[]et ss1[]. À la fin, les lignes restantes du fichier1 sont sorties, préservant l'ordre d'origine.
Dans ce cas, avec le problème indiqué, vous pouvez également diviser et conquérir à l' aide de GNU split(le filtrage est une extension GNU), des exécutions répétées avec des morceaux de fichier1 et la lecture complète de fichier2 à chaque fois:
split -l 20000 --filter='gawk -f linesnotin.awk - file2' < file1
Notez l'utilisation et le placement du -sens stdinsur la gawkligne de commande. Ceci est fourni par à splitpartir de file1 en morceaux de 20000 lignes par appel.
Pour les utilisateurs sur les systèmes non-GNU, il est presque certainement un paquet coreutils GNU , vous pouvez obtenir, y compris sur OSX dans le cadre des d' Apple Xcode outils qui fournit GNU diff, awk, mais seulement un POSIX / BSD splitplutôt que d' une version GNU.
awk 'NR==FNR{a[$0];next}!($0 in a)' file2 file1 > out.txt