Si les fichiers sont triés (ils le sont dans votre exemple) :
comm -23 file1 file2
-23
supprime les lignes qui sont dans les deux fichiers, ou seulement dans le fichier 2. Si les fichiers ne sont pas triés, dirigez-les vers sort
d'abord...
Voir la page de manuel ici
à la rescousse !
Cette solution ne nécessite pas d'entrées triées. Vous devez d'abord fournir le fichier B.
awk 'NR==FNR{a[$0];next} !($0 in a)' fileB fileA
renvoie
A
C
Comment ça marche ?
NR==FNR{a[$0];next}
idiom sert à stocker le premier fichier dans un tableau associatif en tant que clés pour un test "contient" ultérieur.
NR==FNR
vérifie si nous analysons le premier fichier, où le compteur de lignes global (NR) est égal au compteur de lignes de fichier actuel (FNR).
a[$0]
ajoute la ligne actuelle au tableau associatif en tant que clé, notez que cela se comporte comme un ensemble, où il n'y aura pas de valeurs en double (clés)
!($0 in a)
nous sommes maintenant dans le(s) fichier(s) suivant(s),in
est un test contient, ici il vérifie si la ligne actuelle est dans l'ensemble que nous avons rempli dans la première étape à partir du premier fichier,!
annule la condition. Ce qui manque ici est l'action, qui par défaut est{print}
et généralement pas écrit explicitement.
Notez que cela peut maintenant être utilisé pour supprimer les mots de la liste noire.
$ awk '...' badwords allwords > goodwords
avec une légère modification, il peut nettoyer plusieurs listes et créer des versions nettoyées.
$ awk 'NR==FNR{a[$0];next} !($0 in a){print > FILENAME".clean"}' bad file1 file2 file3 ...
Une autre façon de faire la même chose (nécessite également une entrée triée) :
join -v 1 fileA fileB
Dans Bash, si les fichiers ne sont pas pré-triés :
join -v 1 <(sort fileA) <(sort fileB)
grep -Fvxf <lines-to-remove> <all-lines>
- fonctionne sur des fichiers non triés (contrairement à
comm
) - maintient l'ordre
- est POSIX
Exemple :
cat <<EOF > A
b
1
a
0
01
b
1
EOF
cat <<EOF > B
0
1
EOF
grep -Fvxf B A
Sortie :
b
a
01
b
Explication :
-F
:utilisez des chaînes littérales au lieu du BRE par défaut-x
:ne prend en compte que les correspondances correspondant à la ligne entière-v
:impression non correspondante-f file
:prend les motifs du fichier donné
Cette méthode est plus lente sur les fichiers pré-triés que les autres méthodes, car elle est plus générale. Si la vitesse compte également, consultez :Un moyen rapide de trouver des lignes dans un fichier qui ne sont pas dans un autre ?
Voici une automatisation bash rapide pour un fonctionnement en ligne :
remove-lines() (
remove_lines="$1"
all_lines="$2"
tmp_file="$(mktemp)"
grep -Fvxf "$remove_lines" "$all_lines" > "$tmp_file"
mv "$tmp_file" "$all_lines"
)
GitHub en amont.
utilisation :
remove-lines lines-to-remove remove-from-this-file
Voir aussi :https://unix.stackexchange.com/questions/28158/is-there-a-tool-to-get-the-lines-in-one-file-that-are-not-in-another