J’ai 15 fichiers comme
fichier1.csv
a,cg2,0,0,0,21,0 a,cq1,10,0,0,0,0 a,cm2,0,19,0,0,0 ... a,ad10,0,0,0,37,0
fichier2.csv
d,cm1,0,3,0,0,0 d,cs2,0,32,0,0,0 d,cg2,0,0,9,0,0 ... d,az2,0,0,0,21,0
. . . .
file15.csv
s,sd1,0,23,0,0,0 s,cw1,0,0,7,0,0 s,c23,0,0,90,0,0 ... s,cg2,0,45,0,0,0
J’ai un nombre différent de lignes dans chaque fichier et je veux comparer le deuxième champ de tous les 15 fichiers et extraire les lignes qui sont communes au second champ de tous les 15 fichiers.
dans ce cas ci-dessus
la sortie est:
cg2
(en le prenant est commun au deuxième champ de tous les 15 fichiers)
Je suis un peu nouveau à unix et shell script, s’il vous plaît aider
Voulez-vous les lignes complètes de chacun des quinze fichiers où le champ 2 apparaît dans les quinze fichiers? Ou voulez-vous seulement une liste des valeurs du champ 2 qui apparaissent dans les quinze fichiers.
L’ancien:
a,cg2,0,0,0,21,0 d,cg2,0,0,9,0,0 . . . s,cg2,0,45,0,0,0 . . .
Le dernier:
cg2 . . .
Si ce dernier, alors cela devrait fonctionner
awk -F, '{arr[$2]++; if (FILENAME != prevfile) {c++; prevfile = FILENAME}} END {for (i in arr) {if (arr[i] == c) {print i}}}' file*.csv
Cassé sur plusieurs lignes:
awk -F, '{ arr[$2]++; if (FILENAME != prevfile) { c++; prevfile = FILENAME } } END { for (i in arr) { if (arr[i] >= c) { print i } } }' file*.csv
Explication:
>=
au lieu de ==
cela fonctionnera si une valeur apparaît plus d’une fois dans un seul fichier) Modifier:
Voici un moyen d’imprimer les lignes de correspondance complètes en utilisant une technique à deux passes. C’est une modification de la version ci-dessus. Assurez-vous de lister les fichiers deux fois.
awk -F, ' FILENAME == first && flag { exit } ! first { first = FILENAME } FILENAME != first { flag = 1 } { arr[$2]++; if (FILENAME != prevfile) { c++; prevfile = FILENAME } } END { # print the matching lines do { if ($2 in arr) { print; } } while (getline); # print the list of words for (i in arr) { if (arr[i] >= c) { print i } } }' file*.csv file*.csv
Cela dépend du premier fichier du premier groupe qui porte le même nom que le premier fichier du deuxième groupe. L’utilisation de globulation similaire à ce que j’ai montré se chargera de cette exigence.
Il imprime les lignes correspondantes (mais non groupées), puis imprime la liste des mots. Si vous ne voulez que l’un ou l’autre, commentez ou supprimez la boucle que vous ne voulez pas ( do/while
ou for
).
Si vous imprimez uniquement les lignes complètes, vous pouvez canaliser la sortie vers:
sort -t , -k2,2
les regrouper.
Ne canalisant que la liste de mots pour:
sort
les mettra dans le même ordre pour faciliter la comparaison.
Problème amusant
Une façon de le faire, entièrement en Bash, est la suivante.
Une chose que vous devrez invoquer est join -t ',' -1 2 -2 2 file1 file2
pour vous joindre à la deuxième colonne de deux fichiers. Avant de pouvoir participer, vous devez cependant sortinger sur la deuxième colonne.
Effectuez des jointures successives dans une boucle for, car join
ne prend que deux fichiers comme arguments.
ADDENDA
Voici une petite transcription montrant les jointures successives. Vous pouvez l’adapter assez facilement, je pense.
$ cat 1.csv a,b,c,d e,f,g,h i,j,k,l $ cat 2.csv 7,5,4,3 3,b,s,e 2,f,5,5 $ cat 3.csv 4,5,6,7 0,0,0,0 1,b,4,4 $ join -t ',' -1 2 -2 2 1.csv 2.csv | cut -f 1 -d ',' > temp $ cat temp b f $ join -t ',' -2 2 temp 3.csv | cut -f 1 -d ',' b
La première jointure (sur les deux premiers fichiers) produit la valeur jointe dans la première colonne du résultat. Ainsi, lorsque vous vous connectez à file3, file4, file5, etc., vous utiliserez la première colonne du résultat que vous générez, ce qui explique pourquoi vous n’avez besoin que de l’option -2. Pour garder les choses très efficaces, coupez toujours toutes les colonnes sauf la première chaque fois que vous effectuez la jointure.