web-dev-qa-db-fra.com

bash ajouter / ajouter de nouvelles colonnes d'autres fichiers

J'ai un fichier nom.txt d'une colonne, par exemple.

A
B
C
D
E
F

Ensuite, j'ai de nombreux fichiers, par ex. x.txt, y.txt et z.txt

x.txt a

A 1
C 3
D 2

y.txt a

A 1
B 4
E 3

z.txt a

B 2
D 2
F 1

La sortie souhaitable est (remplissage de 0 s'il n'y a pas de cartographie)

A 1 1 0
B 0 4 2
C 3 0 0
D 2 0 2
E 0 3 0
F 0 0 1

Est-il possible de le faire avec Bash? (peut-être awk?)
Merci beaucoup!!!


premières modifications - Mes efforts provisoires
[.____] Comme je suis assez nouveau à bash, il est vraiment difficile de comprendre une solution possible avec Awk. Je connais plus avec R, dans lequel cela peut être accompli par

namematrix[namematrix[,1]==xmatrix[,1],]

Dans l'ensemble, j'apprécie vraiment le type d'aide ci-dessous me aider à en apprendre davantage sur awk et join!


Édite secondaire - Une approche super efficace figurait!

Heureusement, inspiré par certaines réponses vraiment brillantes ci-dessous, j'ai réglé une manière très efficace de calcul que ci-dessous. Cela peut être utile aux autres personnes rencontrant des questions similaires, en particulier si elles traitent avec un très grand nombre de fichiers avec une très grande taille.

Tout d'abord, touchez un join_awk.bash

#!/bin/bash
join -oauto -e0 -a1 $1 $2 | awk '{print $2}'

Par exemple, exécutez ce script Bash pour nom.txt et x.txt

join_awk.bash name.txt x.txt

générerait

1
0
3
2
0
0

Notez que Ici, je ne conservez ici que la deuxième colonne pour économiser de l'espace disque, car dans mon ensemble de données, les premières colonnes sont des noms très longs qui prendraient un espace disque formidable.

Alors simplement implémenter

parallel join_awk.bash name.txt {} \> outdir/output.{} ::: {a,b,c}.txt

Ceci est inspiré de la réponse brillante ci-dessous en utilisant GNU parallel et rejoindre. La différence est que la réponse ci-dessous doit spécifier j1 pour parallel en raison de sa logique annexe série, ce qui ne le rend pas vraiment "parallèle". En outre, la vitesse deviendra plus lente et plus lente à mesure que l'apaisant en série se poursuit. En revanche, nous manipulons ici chaque fichier séparément en parallèle. Il peut être extrêmement rapide lorsque nous traitons avec un grand nombre de fichiers de grande taille avec plusieurs processeurs.

Enfin simplement fusionner tous les fichiers de sortie à une colonne ensemble par

cd outdir
paste output* > merged.txt

Cela sera également très rapide car paste est intrinsèquement parallèle.

18
Elfxy

Avec bash Du faire:

#!/bin/bash

declare -A hash                                 # use an associative array
for f in "x.txt" "y.txt" "z.txt"; do            # loop over these files
    while read -r key val; do                   # read key and val pairs
        hash[$f,$key]=$val                      # assign the hash to val
    done < "$f"
done

while read -r key; do
    echo -n "$key"                              # print the 1st column
    for f in "x.txt" "y.txt" "z.txt"; do        # loop over the filenames
        echo -n " ${hash[$f,$key]:-0}"          # print the associated value or "0" if undefined
    done
    echo                                        # put a newline
done < "name.txt"
1
tshiono