2013-09-04 7 views
0

J'ai un fichier csv que je vais utiliser comme entrée avec un format qui ressemble à ceci:Shell script: copie des colonnes en-tête dans un fichier csv à un autre fichier csv

xValue, valeur1-avg, valeur1-médiane, valeur2-avg, value3-avg, value3-médiane
1,3,4,20,14,20

les attributs clés du fichier d'entrée sont que chaque "valeur" aura un nombre variable de statistiques, mais le type statistique et la "valeur" seront toujours séparés par un "-". Je veux ensuite afficher les statistiques de toutes les "valeurs" pour séparer les fichiers csv.

La sortie serait alors ressembler à quelque chose comme ceci:

value1.csv

xvalue, valeur1-avg, valeur1-médiane
1,3,4

valeur2. csv

xvalue, valeur2-moy
1,20

J'ai essayé de trouver des solutions à cela, mais tout ce que je peux trouver des façons de copier le numéro de colonne, et non pas le nom d'en-tête. Je dois pouvoir utiliser les noms d'en-tête pour ajouter les statistiques associées à chacun des fichiers csv de sortie.

Toute aide est grandement appréciée!

P.S. le fichier de sortie a peut-être déjà été écrit lors des exécutions précédentes de ce script, ce qui signifie que le code doit être ajouté au fichier de sortie

Répondre

2

mais non testé devrait être proche:

awk -F, ' 
NR==1 { 
    for (i=2;i<=NF;i++) { 
     outfile = $i 
     sub(/-.*/,".csv",outfile) 
     outfiles[i] = outfile 
    } 
} 
{ 
    delete(outstr) 
    for (i=2;i<=NF;i++) { 
     outfile = outfiles[i] 
     outstr[outfile] = outstr[outfile] FS $i 
    } 
    for (outfile in outstr) 
     print $1 outstr[outfile] >> outfile 
} 
' inFile.csv 

Notez que la suppression d'un tableau entier avec delete(outstr) est gawk spécifique. Avec d'autres awks, vous pouvez utiliser split("",outstr) pour obtenir le même effet. Notez que cela ajoute la sortie voulue aux fichiers existants MAIS cela signifie que vous obtiendrez la ligne d'en-tête répétée à chaque exécution.Si c'est un problème, nous dire comment savoir quand pour générer la ligne d'en-tête ou non, mais la solution, je pense que vous aurez envie ressemblerait à quelque chose comme ceci:

awk -F, ' 
NR==1 { 
    for (i=2;i<=NF;i++) { 
     outfile = $i 
     sub(/-.*/,".csv",outfile) 
     outfiles[i] = outfile 
    } 
    for (outfile in outfiles) { 
     exists[outfile] = (((getline tmp < outfile) > 0) && (tmp != "")) 
     close(outfile) 
    } 
} 
{ 
    delete(outstr) 
    for (i=2;i<=NF;i++) { 
     outfile = outfiles[i] 
     outstr[outfile] = outstr[outfile] FS $i 
    } 
    for (outfile in outstr) 
     if ((NR > 1) || !exists[outfile]) 
      print $1 outstr[outfile] >> outfile 
} 
' inFile.csv 
+0

Comment puis-je invoquer ce exactement à travers le terminal? J'essaie actuellement sh test.sh inFile.csv values1.csv values2.csv values3.csv – user1553248

+0

Tout ce que vous avez à faire est ./test.sh. J'ai renommé le fichier d'entrée en réponse pour correspondre à ce que vous essayez d'utiliser. –

0

Déterminez le nom associé à chaque colonne et utilisez ce mappage pour manipuler les colonnes. Si vous essayez de faire cela dans awk, vous pouvez utiliser des tableaux associatifs pour stocker les noms de colonnes et les lignes correspondantes. Si vous utilisez ksh93 ou bash, vous pouvez utiliser des tableaux associatifs pour stocker les noms de colonnes et les lignes correspondantes. Si vous utilisez perl, python ou ruby ​​ou ... vous pouvez ...

Ou de pousser les colonnes dans un tableau pour faire correspondre les nombres aux numéros de colonne. Dans les deux cas, vous disposez d'une liste d'en-têtes de colonnes, que vous pouvez ensuite manipuler.

0

La solution que j'ai trouvé le plus utile à ce genre Le problème consiste à récupérer d'abord le numéro de colonne à l'aide d'un script AWK (encapsulé dans une fonction shell), puis à suivre une instruction cut. Cette technique/stratégie se transforme en une solution très concise, générale et rapide qui peut tirer profit du co-traitement. Le cas non-append est plus propre, mais voici un exemple qui gère la complication du append que vous avez mentionné:

#! /bin/sh 
fields() { 
     LC_ALL=C awk -F, -v pattern="$1" '{ 
       j=0; split("", f) 
       for (i=1; i<=NF; i++) if ($(i) ~ pattern) f[j++] = i 
       if (j) { 
         printf("%s", f[0]) 
         for (i=1; i<j; i++) printf(",%s", f[i]) 
       } 
       exit 0 
     }' "$2" 
} 
cut_fields_with_append() { 
     if [ -s "$3" ] 
     then 
       cut -d, -f `fields "$1" "$2"` "$2" | sed '1 d' >> "$3" 
     else 
       cut -d, -f `fields "$1" "$2"` "$2" > "$3" 
     fi 
} 
cut_fields_with_append '^[^-]+$|1-' values.csv value1.csv & 
cut_fields_with_append '^[^-]+$|2-' values.csv value2.csv & 
cut_fields_with_append '^[^-]+$|3-' values.csv value3.csv & 
wait 

Le résultat est que vous attendez:

$ ls 
values values.csv 
$ cat values.csv 
xValue,value1-avg,value1-median,value2-avg,value3-avg,value3-median 
1,3,4,20,14,20 
$ ./values 
$ ls 
value1.csv value2.csv value3.csv values values.csv 
$ cat value1.csv 
xValue,value1-avg,value1-median 
1,3,4 
$ cat value2.csv 
xValue,value2-avg 
1,20 
$ cat value3.csv 
xValue,value3-avg,value3-median 
1,14,20 
$ ./values 
$ cat value1.csv 
xValue,value1-avg,value1-median 
1,3,4 
1,3,4 
$ cat value2.csv 
xValue,value2-avg 
1,20 
1,20 
$ cat value3.csv 
xValue,value3-avg,value3-median 
1,14,20 
1,14,20 
$ 
Questions connexes