J'ai "test1.csv" et il contient
200,400,600,800
100,300,500,700
50,25,125,310
et test2.csv et il contient
100,4,2,1,7
200,400,600,800
21,22,23,24,25
50,25,125,310
50,25,700,5
à présent
diff test2.csv test1.csv > result.csv
est différent de
diff test1.csv test2.csv > result.csv
Je ne sais pas quel est le bon ordre, mais je veux quelque chose d'autre, les deux commandes ci-dessus afficheront quelque chose comme
2 > 100,4,2,1,7
3 2,3c3,5
4 < 100,300,500,700
5 < 50,25,125,310
6 \ No newline at end of file
7 ---
8 > 21,22,23,24,25
9 > 50,25,125,310
Je veux afficher uniquement la différence, ainsi results.csv devrait ressembler à ceci
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5
J'ai essayé diff -q
et diff -s
mais ils ne l'ont pas fait. L'ordre n'a pas d'importance, ce qui compte, c'est que je ne souhaite voir que la différence, ni> ni <ni un espace.
grep -FvF
a fait le tour des petits fichiers, pas des gros
le premier fichier contient plus de 5 millions de lignes, le second 1300.
donc results.csv devrait aboutir à environ 4 998 700 lignes
J'ai aussi essayé grep -F -x -v -f
qui n'a pas fonctionné.
Cela ressemble à un travail pour comm
:
$ comm -3 <(sort test1.csv) <(sort test2.csv)
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5
Comme expliqué dans man comm
:
-1 suppress column 1 (lines unique to FILE1)
-2 suppress column 2 (lines unique to FILE2)
-3 suppress column 3 (lines that appear in both files)
Donc, le -3
signifie que seules les lignes uniques à l'un des fichiers seront imprimées. Cependant, ceux-ci sont mis en retrait en fonction du fichier dans lequel ils ont été trouvés. Pour supprimer l'onglet, utilisez:
$ comm -3 <(sort test1.csv) <(sort test2.csv) | tr -d '\t'
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5
Dans ce cas, vous n'avez même pas vraiment besoin de trier les fichiers et vous pouvez simplifier ce qui précède pour:
comm -3 test1.csv test2.csv | tr -d '\t' > difference.csv
Utilisation de grep
avec bash
name__:
$ cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv)
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5
Pour enregistrer le résultat sous results.csv
:
cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv) >results.csv
<()
est le modèle de substitution de processus bash
NAME_
grep -vFf test2.csv test1.csv
trouvera les lignes uniques à seulement test1.csv
grep -vFf test1.csv test2.csv
trouvera les lignes uniques à seulement test2.csv
Enfin, nous résumons les résultats par cat
name__
Ou comme Oli a suggéré , vous pouvez également utiliser le groupement de commandes:
$ { grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv; }
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5
Ou alors, courez les uns après les autres, car ils écrivent tous les deux sur STDOUT, ils seront finalement ajoutés:
$ grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5
--*-line-format=...
de diff
name__Vous pouvez indiquer à diff
exactement ce dont vous avez besoin - comme expliqué ci-dessous:
diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' f1.txt f2.txt
Il est possible de spécifier la sortie de diff de manière très détaillée, semblable à un format de numéro printf
name__.
Les lignes du premier fichier, test1.csv
sont appelées "anciennes" lignes et les lignes du deuxième fichier, test2.csv
, sont des "nouvelles" lignes. Cela a du sens lorsque diff
est utilisé pour voir ce qui a changé dans un fichier.
Les options dont nous avons besoin sont celles qui permettent de définir le format des "anciennes" lignes, des "nouvelles" lignes et des lignes "inchangées".
Les formats dont nous avons besoin sont très simples:
Pour les lignes modifiées, nouvelles et anciennes, nous ne voulons afficher que le texte des lignes. %L
est le symbole de format pour le texte de la ligne.
Pour les lignes inchangées, nous ne voulons rien afficher.
Avec cela, nous pouvons écrire des options comme --old-line-format='%L'
, et les mettre ensemble, en utilisant vos données d'exemple:
$ diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' test1.csv test2.csv
100,4,2,1,7
100,300,500,700
21,22,23,24,25
50,25,700,5
Étant donné que les fichiers ont une taille différente, essayez d'échanger les fichiers d'entrée si cela n'a pas d'importance, il se peut que le fonctionnement interne de diff
puisse gérer une manière mieux que l'autre. Mieux vaut avoir moins de mémoire ou moins de calculs.
Il existe une option d'optimisation pour utiliser diff
avec des fichiers volumineux: --speed-large-files
. Il utilise des hypothèses sur la structure du fichier, il n'est donc pas clair si cela vous aide, mais cela vaut la peine de l'essayer.
Les options de format sont décrites dans le man diff
sous --LTYPE-line-format=LFMT
.
Si l'ordre des lignes n'est pas pertinent, utilisez awk
ou Perl
:
awk '{seen[$0]++} END {for (i in seen) {if (seen[i] == 1) {print i}}}' 1.csv 2.csv
Utilisez grep
pour obtenir les lignes communes et les filtrer:
grep -hxvFf <(grep -Fxf 1.csv 2.csv) 1.csv 2.csv
Le grep interne obtient les lignes communes, puis le grep externe trouve les lignes qui ne correspondent pas à ces lignes communes.
Puisque la commande n'a pas besoin d'être préservée, simplement:
sort test1.csv test2.csv | uniq -u
sort test1.csv test2.csv
: fusionne et trie test1.csv
et test2.csv
uniq -u
: imprime uniquement les lignes sans doublon