Collez des colonnes UNIX et insérez des zéros pour toutes les valeurs manquantes.

Je voudrais merge des colonnes spécifiques à partir de deux files txt contenant un nombre variable de lignes, mais le même nombre de colonnes (comme indiqué ci-dessous):

file1: xyz desc1 12 uvw desc2 55 pqr desc3 12 file2: xyz desc1 56 uvw desc2 88 Preferred output: xyz desc1 12 56 uvw desc2 55 88 pqr desc3 12 0 

Actuellement, j'utilise la command paste en utilisant awk comme:

  paste <(awk '{print $1}' file1) <(awk '{print $2}' file1) <(awk '{print $3}' file1) <(awk '{print $3}' file2) 

Mais cela semble ne merge que les colonnes qui se chevauchent. Existe-t-il un moyen d'insert des zéros au lieu d'omettre la ligne elle-même?

J'ai besoin de combiner 100 files set de sorte que mon file de sortie contiendra 102 colonnes.

Si l'ordre des colonnes est important, c.-à-d. Que les numéros du même file doivent être conservés dans la même colonne, vous devez append un remplissage en lisant les différents files. Voici une façon qui fonctionne avec GNU awk:

merge.awk

 # Set k to be a shorthand for the key { k = $1 SUBSEP $2 } # First element with this key, add zeros to align it with other rows !(k in h) { for(i=1; i<=ARGIND-1; i++) h[k] = h[k] OFS 0 } # Remember the data element { h[k] = h[k] OFS $3 } # Before moving to the next file, ensure that all rows are aligned ENDFILE { for(k in h) { if(split(h[k], a) < ARGIND) h[k] = h[k] OFS 0 } } # Print out the collected data END { for(k in h) { split(k, a, SUBSEP) print a[1], a[2], h[k] } } 

Voici quelques files de test: f1 , f2 , f3 et f4 :

 $ tail -n+1 f[1-4] ==> f1 <== xyz desc1 21 uvw desc2 22 pqr desc3 23 ==> f2 <== xyz desc1 56 uvw desc2 57 ==> f3 <== xyz desc1 87 uvw desc2 88 ==> f4 <== xyz desc1 11 uvw desc2 12 pqr desc3 13 stw desc1 14 arg desc2 15 

Test 1

 awk -f merge.awk f[1-4] | column -t 

Sortie:

 pqr desc3 23 0 0 13 uvw desc2 22 57 88 12 stw desc1 0 0 0 14 arg desc2 0 0 0 15 xyz desc1 21 56 87 11 

Test 2

 awk -f merge.awk f2 f3 f4 f1 | column -t 

Sortie:

 pqr desc3 0 0 13 23 uvw desc2 57 88 12 22 stw desc1 0 0 14 0 arg desc2 0 0 15 0 xyz desc1 56 87 11 21 

Modifier:

Si la sortie doit être séparée par des tabulations, réglez le séparateur de champ de sortie en conséquence:

 awk -f merge.awk OFS='\t' f[1-4] 

Essaye ça:

 $ awk ' FNR == NR { a[$1,$2] = $3; next } { print $0,(($1,$2) in a) ? a[$1,$2] : "0" } ' file2 file1 xyz desc1 12 56 uvw desc2 55 88 pqr desc3 12 0 

C'est un peu long, mais ça marche:

 $ cat file1 file2 | awk '{a[$1FS$2]=a[$1FS$2]FS$3; b[$1FS$2]++} END {for (i in b) max=max<b[i]?b[i]:max; for (i in a) {printf "%s %s", i, a[i]; for (j=b[i]; j<max; j++) printf "%s0", FS printf "%s", RS}}' pqr desc3 12 0 xyz desc1 12 56 uvw desc2 55 88 

Le bloc awk peut être formaté comme suit:

 awk '{a[$1FS$2]=a[$1FS$2]FS$3; b[$1FS$2]++} END {for (i in b) max=max<b[i]?b[i]:max for (i in a) {printf "%s%s%s", i, FS, a[i] for (j=b[i]; j<max; j++) printf "%s0", FS printf "%s", RS} }' 

L'idée est d'imprimer tous les files, puis d'attraper les valeurs répétées dans le tableau a[$1 $2] . En outre, b[$1 $2] contient la quantité de fois qu'une paire ( $1 , $2 ) est apparue.

Dans le bloc END{} , nous continuons à boucler les valeurs et à compléter avec autant de 0 s qui manquent du nombre d'éléments au nombre maximum d'éléments.