Je sais que cette question a déjà été posée plusieurs fois. Voici un exemple:
Utilisation d'AWK pour fusionner deux fichiers basés sur plusieurs colonnes
Mon objectif est d'imprimer les colonnes 2, 4, 5 et 7 de file_b et les colonnes 17 et 18 de file_a si la correspondance suivante se produit: Les colonnes 2, 6 et 7 de file_a.csv correspondent respectivement aux colonnes 2, 4 et 5 de file_b.csv.
Mais peu importe ce que j'essaye, je ne peux pas le faire fonctionner pour mon cas . Voici mes deux fichiers:
file_a.csv
col2, col4, col5, col7, a, b, c, 4.5, e, f, g, 6.3,
file_b.csv
awk -F, -v RS='\r\n' 'NR==FNR{key[$2 FS $6 FS $7]=$17 FS $18;next} {if($2 FS $4 FS $5 in key); print $2 FS $4 FS $5 FS $7 FS key[$2 FS $6 FS $7]}' file_a.csv file_b.csv > out.csv
Sortie devrait ressembler à ceci:
col2, col4, col5, col7, col17, col18 a, b, c, 4.5, 145, 88 e, f, g, 6.3, 101, 96
J'ai essayé ceci:
col2, col4, col5, col7 a, b, c, 4.5 e, f, g, 6.3 x, k, l, 12.9
Actuellement, le résultat que j'obtiens est: p >
col2, col6, col7, col17, col18 a, b, c, 145, 88 e, f, g, 101, 96 x, y, z, 243, 222
En d'autres termes, col17 et col18 de file_a n'apparaissent pas.
Hier, j'ai posé une question connexe où j'avais des problèmes avec les sauts de ligne. Cela a été résolu et résolu, mais maintenant je pense que ce problème est lié à la vérification de la condition if.
Mise à jour: Je partage des liens vers des copies tronquées des données réelles. La seule différence entre ces fichiers et les fichiers réels est que les vrais ont des millions de lignes. Ceux-ci n'en ont que 10 chacun.
3 Réponses :
Veuillez essayer ceci (GNU sed):
dos2unix file
C'est le moment où le bloc BEGIN
entre en jeu. OFS
entre également en jeu.
Lorsque nous imprimons de nombreux champs séparés par la même chose, nous pouvons définir OFS
, et simplement mettre une virgule entre les éléments que nous voulons imprimer.
Il n'est pas nécessaire de vérifier clé dans arr
lorsque vous avez attribué une valeur à une clé du tableau,
par défaut, lorsque arr [somekey]
n'est pas affecté auparavant, il est vide
/ ""
, et il est évalué à false dans awk (
dans 0
dans un contexte scalaire), et une chaîne non vide est évaluée à true
(il n'y a pas littéralement de true
et false awk
).
(Vous avez utilisé un nom de array
incorrect, le $ 2, $ 6, $ 7
est la clé dans le tableau arr
ici. Il est déroutant d'utiliser clé
comme nom de tableau.)
Vous pouvez tester un concept simple comme celui-ci:
sed -i 's/\r//' files
Vous n'avez pas besoin d'un fichier d'entrée pour exécuter le bloc BEGIN
.
De plus, vous pouvez parfois utiliser des guillemets, pour éviter toute confusion et problème sous-jacent.
Mise à jour :
Vos fichiers se terminent en fait par \ n
, si vous ne pouvez pas être sûr de la fin de la ligne, utilisez ceci:
awk 'BEGIN{RS="[\r\n]+";FS=OFS=",";SUBSEP=FS}NR==FNR{arr[$2,$6,$7]=$17 FS $18;next} {if(arr[$2,$4,$5]) print $2,$4,$5,$7,arr[$2,$4,$5]}' file_a.csv file_b.csv
ou ceci (This on ignorera les lignes vides):
awk 'BEGIN{RS="\r\n|\n|\r";FS=OFS=",";SUBSEP=FS}NR==FNR{arr[$2,$6,$7]=$17 FS $18;next} {if(arr[$2,$4,$5]) print $2,$4,$5,$7,arr[$2,$4,$5]}' file_a.csv file_b.csv
Aussi , il vaut mieux d'abord convertir pour éviter de telles situations, en:
awk 'BEGIN{print arr["newkey"]}'
Ou vous pouvez utiliser la commande dos2unix
:
awk 'BEGIN{RS="\r\n";FS=OFS=",";SUBSEP=FS}NR==FNR{arr[$2,$6,$7]=$17 FS $18;next} {if(arr[$2,$4,$5]) print $2,$4,$5,$7,arr[$2,$4,$5]}'
C'est un outil de ligne de commande pratique pour faire ce qui précède uniquement.
Vous pouvez l'installer si vous ne l'avez pas encore dans votre système.
Une fois converti, vous n'avez pas besoin d'attribuer RS
dans des situations normales.
Ca ne fonctionne pas. Maintenant, j'obtiens un fichier vide en sortie. J'ai ajouté les noms de fichiers à la fin de votre code: file_a.csv file_b.csv> out.csv
J'ai ajouté des données réelles maintenant. Veuillez jeter un œil.
Fonctionne parfaitement maintenant. Mais je suis confus au sujet de \ r et \ n. Suite au commentaire de RavinderSingh13 ci-dessus, j'ai essayé de supprimer "CR" et "LF" (comme indiqué dans Notepad ++). J'ai réussi à supprimer CR mais pas LF. Ai-je raison de dire que CR = / n et LF = / r? Est-ce que / n = nouvelle ligne? Qu'est-ce que / r alors?
CR
= \ r
, LF
= \ n
. Différentes fins de ligne. Conventionnel: Windows: \ r \ n
, linux: \ n
, macOS: \ r
(je ne suis pas sûr de celui-ci). Ce sont des caractères différents qui font la même chose aujourd'hui. (Dans l'ancien temps, le chariot signifie passer au début de la ligne, retourner signifie passer à la ligne suivante.) @Ahmed_m
Merci. Dernière question: que signifient [] et le + dans RS = "[\ r \ n] +"?
@ahmed_m []
signifie tout caractère qu'il contient (ou tout autre lorsque commence par ^
à l'intérieur). +
signifie une ou plusieurs occurrences
. Recherchez Regex
pour en savoir plus.
$ awk 'BEGIN {RS="\r\n"; FS=OFS=","} NR==FNR {a[$2,$6,$7]=$17 OFS $18; next} ($2,$4,$5) in a {print $2,$4,$5,$7,a[$2,$4,$5]}' file1 file2 > output Your main issue is, in the array lookup the index you should use is the second file key, not the first file key. Also the semicolon after the if condition is wrong. The rest is cosmetics only. Not sure you want the output \r\n terminated, if so set ORS=RS as well, otherwise it's newline only.
Puisque vous avez mentionné que le fichier est énorme, vous pouvez essayer Perl, si c'est une option.
Les fichiers sont supposés avoir "\ r".
$ cat file_a.csv col2, col6, col7, col17, col18 a, b, c, 145, 88 e, f, g, 101, 96 x, y, z, 243, 222 $ cat file_b.csv col2, col4, col5, col7 a, b, c, 4.5 e, f, g, 6.3 x, k, l, 12.9 $ perl -F, -lane 'BEGIN { %kv=map{chomp;chop;@a=split(",");"$a[0],$a[1],$a[2]"=>"$a[3]"} qx(cat file_b.csv) } if($.>1){ $x="$F[0],$F[1],$F[2]";chomp($F[-1]);print "$x,$kv{$x}",join(",",@F[-2,-1]) if $kv{$x} } ' file_a.csv a, b, c, 4.5 145, 88 e, f, g, 6.3 101, 96 $
Avez-vous besoin de caractères
\ r
dans votre (vos) fichier (s) d'entrée? Sinon, débarrassez-vous-en d'abord en utilisanttr -d '\ r' temp && mv temp Input_file
. Imprimez égalementawk '{print $ 17, $ 18}' Input_file
pour voir que vous obtenez une sortie comme des désirs, laissez-nous knoe alors?Merci @ RavinderSingh13. Voir mon commentaire sur la réponse de Tiw ci-dessous.