Esiste un'utilità della riga di comando per trasporre un file CSV?


16

Dato un file come questo

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

Esiste un'utilità della riga di comando per trasporre i contenuti in modo che l'output appaia così

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

Risposte:


6
ruby -rcsv -e 'puts CSV.parse(STDIN).transpose.map &:to_csv' < in.csv > out.csv

Data l'età di questa domanda, giustificherò il mio passaggio a questo come accettata: a) Questa risposta è molto più concisa di quella di Gilles python, b) rubynon è meno portatile di python, ec) questo mostra anche come passare l'input / output File. Bravo @luikore, e benvenuto su Unix e Linux. Per favore, restate in giro.
Cory Klein,

un avvertimento, nel CSV, i campi devono essere citati
yosefrow

@yosefrow Non c'è bisogno di citare. Ho testato il comando prima di pubblicare questa risposta.
luikore,

ok avrebbe dovuto dire "maggio" allora. Non ha funzionato per me fino a quando non ho elencato tutti i campi. Potrebbe avere a che fare con il contenuto dei miei dati
yosefrow il

16

L'analisi CSV non viene eseguita facilmente solo con gli strumenti POSIX, a meno che non si stia utilizzando una variante CSV semplificata senza virgolette (quindi le virgole non possono apparire in un campo). Anche allora questo compito non sembra facile da fare con awk o altri strumenti di elaborazione del testo. Puoi usare Perl con Text::CSV, Python con csv, R con read.csv, Ruby con CSV , ... (Tutti questi fanno parte della libreria standard del rispettivo linguaggio ad eccezione di Perl.)

Ad esempio, in 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])


3

Una soluzione veloce e sporca :

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++))
}

cosa rappresenta / tmp / l? Inoltre, non sarebbe più semplice scorrere tra le colonne piuttosto che le linee, qualcosa lungo le righe difor ((i=1; i<=$num_cols; ++i)); do paste -s -d, <(cut -f$i -d, file.txt); done
iruvar

Si noti che questo funziona per l'input di OP, ma solo perché i loro dati hanno lo stesso numero di righe e colonne, che di solito non è il caso.
tokland

csv ha specifiche per quanto riguarda le virgolette doppie, cioè la this "is" examplecella è codificata "this ""is"" example"Non sono convinto che questa soluzione gestisca correttamente questi casi
Grzegorz Wierzowiecki,

0

Data la limitazione suggerita (senza virgolette, senza virgole incorporate), è semplice in awk (come sarebbe in perl non tenendo conto di oltre mille righe in CSV.pm, 2300 righe in csv.rb- python ha solo 450 righe in csv.py).

Ecco un esempio di 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];
    }
}

A proposito: l'esempio dato aveva spazio extra che OP supponeva fosse rimosso; gli altri esempi non hanno affrontato questo dettaglio.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.