Je suis sûr que j’ai déjà trouvé une commande unix capable d’imprimer les lignes communes à partir de deux fichiers ou plus. Quelqu'un connaît-il son nom? C'était beaucoup plus simple que diff
.
La commande que vous recherchez est comm
. par exemple:-
comm -12 1.sorted.txt 2.sorted.txt
Ici:
- 1 : supprime la colonne 1 (lignes uniques à 1.sorted.txt)
- 2 : supprime la colonne 2 (lignes uniques à 2.sorted.txt)
Pour appliquer facilement la commande comm aux fichiers non triés , utilisez les commandes de Bash - substitution de processus :
$ bash --version
GNU bash, version 3.2.51(1)-release
Copyright (C) 2007 Free Software Foundation, Inc.
$ cat > abc
123
567
132
$ cat > def
132
777
321
Les fichiers abc et def ont donc une ligne commune, celle avec "132". Utilisation de comm sur des fichiers non triés:
$ comm abc def
123
132
567
132
777
321
$ comm -12 abc def # No output! The common line is not found
$
La dernière ligne n'a généré aucune sortie, la ligne commune n'a pas été découverte.
Maintenant, utilisez comm sur les fichiers triés, en triant les fichiers avec substitution de processus:
$ comm <( sort abc ) <( sort def )
123
132
321
567
777
$ comm -12 <( sort abc ) <( sort def )
132
Maintenant, nous avons la ligne 132!
Pour compléter le Perl one-liner, voici son équivalent awk
:
awk 'NR==FNR{arr[$0];next} $0 in arr' file1 file2
Cela lira toutes les lignes de file1
dans le tableau arr[]
, puis vérifiez chaque ligne de file2
s'il existe déjà dans le tableau (c'est-à-dire file1
). Les lignes trouvées seront imprimées dans l'ordre dans lequel elles apparaissent dans file2
. Notez que la comparaison in arr
utilise la ligne entière de file2
en tant qu'index du tableau, il ne signalera que les correspondances exactes sur des lignes entières.
Peut-être que vous voulez dire comm
?
Comparez les fichiers triés FILE1 et FILE2 ligne par ligne.
En l'absence d'options, créez une sortie sur trois colonnes. La première colonne contient des lignes uniques à FILE1, la deuxième colonne contient des lignes uniques à FILE2 et la troisième colonne contient des lignes communes aux deux fichiers.
Le secret pour trouver ces informations sont les pages d’informations. Pour les programmes GNU, ils sont beaucoup plus détaillés que leurs pages de manuel. Essayez info coreutils
et il vous listera tous les petits utilitaires utiles.
Tandis que
grep -v -f 1.txt 2.txt > 3.txt
vous donne les différences de deux fichiers (ce qui est dans 2.txt et non dans 1.txt), vous pouvez facilement faire un
grep -f 1.txt 2.txt > 3.txt
pour collecter toutes les lignes communes, ce qui devrait fournir une solution simple à votre problème. Si vous avez trié les fichiers, vous devriez néanmoins prendre comm
. Cordialement!
Si les deux fichiers ne sont pas encore triés, vous pouvez utiliser:
comm -12 <(sort a.txt) <(sort b.txt)
et cela fonctionnera en évitant le message d'erreur comm: file 2 is not in sorted order
en faisant comm -12 a.txt b.txt
.
Perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' file1 file2
awk 'NR==FNR{a[$1]++;next} a[$1] ' file1 file2
Sur une version limitée de Linux (comme un QNAP (nas) sur lequel je travaillais):
grep -f file1 file2
peut causer des problèmes, comme l’a dit @ChristopherSchultz, en utilisant grep -F -f file1 file2
était vraiment lent (plus de 5 minutes - pas terminé - plus de 2-3 secondes avec la méthode ci-dessous pour les fichiers de plus de 20 Mo)Alors voici ce que j'ai fait:
sort file1 > file1.sorted
sort file2 > file2.sorted
diff file1.sorted file2.sorted | grep "<" | sed 's/^< *//' > files.diff
diff file1.sorted files.diff | grep "<" | sed 's/^< *//' > files.same.sorted
Si files.same.sorted
doit avoir été dans le même ordre que celui d'origine, puis ajouter cette ligne pour le même ordre que fichier1:
awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file1 > files.same
ou, pour le même ordre que file2:
awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file2 > files.same
Juste pour référence si quelqu'un cherche toujours comment faire cela pour plusieurs fichiers, voir la réponse liée à Recherche des lignes correspondantes sur plusieurs fichiers.
En combinant ces deux réponses ( ans1 et ans2 ), je pense que vous pouvez obtenir le résultat souhaité sans trier les fichiers:
#!/bin/bash
ans="matching_lines"
for file1 in *
do
for file2 in *
do
if [ "$file1" != "$ans" ] && [ "$file2" != "$ans" ] && [ "$file1" != "$file2" ] ; then
echo "Comparing: $file1 $file2 ..." >> $ans
Perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' $file1 $file2 >> $ans
fi
done
done
Enregistrez-le simplement, donnez-lui les droits d'exécution (chmod +x compareFiles.sh
) et lancez-le. Il prendra tous les fichiers présents dans le répertoire de travail en cours et fera une comparaison générale en laissant dans le fichier "matching_lines" le résultat.
Les choses à améliorer: