Existe-t-il un utilitaire de ligne de commande pour transposer un fichier csv?

16

Étant donné un fichier comme ça

First,Last,Age
Cory,Klein,27
John Jacob,Smith,30

Existe-t-il un utilitaire de ligne de commande pour transposer le contenu afin que la sortie apparaisse comme telle

First,Cory,John Jacob
Last,Klein,Smith
Age,27,30
Cory Klein
la source

Réponses:

6
ruby -rcsv -e 'puts CSV.parse(STDIN).transpose.map &:to_csv' < in.csv > out.csv
luikore
la source
Compte tenu de l'âge de cette question, je justifierai mon passage à celui-ci comme étant accepté: a) Cette réponse est beaucoup plus succincte que celle de Gilles python, b) rubyn'est pas moins portable que python, et c) cela montre également comment passer les entrées / sorties des dossiers. Bravo @luikore, et bienvenue sur Unix et Linux. Veuillez rester.
Cory Klein
une mise en garde, dans le csv, les champs doivent être cités
yosefrow
@yosefrow Pas besoin de citer. J'ai testé la commande avant de poster cette réponse.
luikore
ok aurait dû dire "peut" alors. Cela n'a pas fonctionné pour moi jusqu'à ce que je cite tous les champs. Pourrait avoir à voir avec mon contenu de données
yosefrow
16

L'analyse CSV n'est pas facile à faire avec les outils POSIX uniquement, sauf si vous utilisez une variante CSV simplifiée sans guillemets (de sorte que les virgules ne puissent pas apparaître dans un champ). Même alors, cette tâche ne semble pas facile à faire avec un outil de traitement de texte ou un autre outil. Vous pouvez utiliser Perl avec Text::CSV, Python avec csv, R avec read.csv, Ruby avec CSV ,… (Tous ces éléments font partie de la bibliothèque standard du langage respectif à l'exception de Perl.)

Par exemple, en Python:

import csv, sys
rows = list(csv.reader(sys.stdin))
writer = csv.writer(sys.stdout)
for col in xrange(0, len(rows[0])):
    writer.writerow([row[col] for row in rows])
Gilles 'SO- arrête d'être méchant'
la source
11

Depuis /programming//a/2776078 :

$ apt-get install csvtool

Et puis convertir

$ csvtool transpose input.csv > ouput.csv

Ou en cours

$ ... | csvtool transpose - | ...
Grzegorz Wierzowiecki
la source
1
magnifique. Seul ... | csvtranspose | ...battrait cela, au niveau de la syntaxe.
masterxilo
3

Une solution rapide et sale :

c=1
file=file.txt
num_lines=$(wc -l < "$file")

for ((i=0; i<num_lines; i++)) {
    cut -d, -f$c "$file" | paste -sd ','
    ((c++))
}
Gilles Quenot
la source
que représente / tmp / l? De plus, ne serait-il pas plus simple de parcourir les colonnes plutôt que les lignes, quelque chose le long des lignes defor ((i=1; i<=$num_cols; ++i)); do paste -s -d, <(cut -f$i -d, file.txt); done
iruvar
Notez que cela fonctionne pour l'entrée OP, mais uniquement parce que leurs données ont le même nombre de lignes et de colonnes, ce qui n'est généralement pas le cas.
Tokland
csv a des spécifications concernant les guillemets doubles, c'est- this "is" exampleà- dire que la cellule est encodée "this ""is"" example"Je ne suis pas convaincu si cette solution gère correctement ces cas
Grzegorz Wierzowiecki
0

Compte tenu de la limitation suggérée (pas de guillemets, pas de virgules imbriquées), c'est simple en awk (comme ce serait en perl sans prendre en compte plus de mille lignes en CSV.pm, 2300 lignes en csv.rb- python n'a que 450 lignes csv.py).

Voici un exemple pour awk:

#!/usr/bin/awk -f
BEGIN { width=0; }
{
    max = split($0, list, ",");
    # printf "%d:%s\n", NR, $0;
    if (width < max)
        width = max;
    for (n = 1; n <= max; ++n) {
        sub("^[     ]*","",list[n]);
        sub("[  ]*$","",list[n]);
        # printf "\t%d:%s\n", n, list[n];
        if ( columns[n] != "" ) {
            columns[n] = columns[n] ", ";
        }
        columns[n] = columns[n] list[n];
    }
}
END {
    # printf "%d columns\n", width;
    for (n = 1; n <= width; ++n) {
        printf "%s\n", columns[n];
    }
}

Soit dit en passant: l'exemple donné avait de l'espace supplémentaire que OP supposait être supprimé; les autres exemples n'ont pas abordé ce détail.

Thomas Dickey
la source