Come posso convertire i dati delimitati da tabulazioni in dati delimitati da virgole?


8

Sto richiedendo un elenco di istantanee ec2 tramite lo strumento da riga di comando ec2 di amazon:

ec2-describe-snapshots -H --hide-tags > snapshots.csv

I dati sono simili al seguente:

SnapshotId      VolumeId        StartTime   OwnerId         VolumeSize  Description
snap-00b66464   vol-b99a38d0    2012-01-05  5098939         160         my backup

Come posso intercettare i dati prima di reindirizzarli snapshots.csve fare le seguenti cose:

  • sostituire "tabs" con virgole
  • incapsulare i valori con le virgolette
  • se un valore è costituito da tutti i numeri, aggiungilo come prefisso in =modo che Excel lo tratterà come testo, ad esempio OwnerIddovrebbe essere "=5098939"(questo non è necessario se non può essere eseguito in linea e richiederebbe invece un file di script o una funzione)

output desiderato:

"SnapshotId","VolumeId","StartTime","OwnerId","VolumeSize","Description"
"snap-00b66464","vol-b99a38d0","2012-01-05","=5098939","=160","my backup"

Qui è dove qualcuno ti dice di importare usando le schede. O lo farebbero, se Excel non fosse in crisi.
Ignacio Vazquez-Abrams,

Sì, sto cercando di aiutare a eccellere un po 'dal momento che non sembra essere così caldo da solo. Anche avere un file CSV che può essere appena aperto invece di dover usare il comando di menu di importazione è sempre bello. Ho già provato a cambiare l'estensione in ".tsv" senza fortuna.
Cwd,

Penso che l'output desiderato sia un po 'fuori. Ci sono molti campi vuoti lì dentro (le virgolette vuote).
Patrick

Risposte:


10
#!/usr/bin/awk -f

BEGIN { FS = "\t"; OFS = "," }
{
    for(i = 1; i <= NF; i++) {
        if ($i + 0 == $i) { $i = "=" $i }
        else gsub(/"/, "\"\"", $i);
        $i = "\"" $i "\""
    }
    print
}

Supponendo che tu lo chiami convert.awk, puoi chiamare con entrambi

ec2-describe-snapshots -H --hide-tags | awk -f convert.awk > snapshots.csv

o (dopo aver aggiunto le autorizzazioni di esecuzione chmod a+x convert.awk)

ec2-describe-snapshots -H --hide-tags | ./convert.awk > snapshots.csv

Ciò creerà una nuova colonna per ogni scheda, che manterrà insieme la colonna dei commenti (a meno che non contenga schede), ma aggiunga colonne vuote (anche se è così che appare l'output di esempio, quindi forse lo desideri davvero). Se vuoi dividere su tutto lo spazio bianco (questo comprimerà le schede extra all'interno della tabella ma inserirà ogni parola nella descrizione come una nuova colonna), estrai l' FS="\t";istruzione.

Per le generazioni future, se non è necessario il "s o =s o spazi incorporato, si può fare una battuta:

awk -v OFS=, '{$1=$1;print}'

Bella soluzione pulita. Pensavo che sarebbe stato molto più brutto di così, ma poi non sono una persona strana :-)
Patrick,

quindi posso salvarlo in un file come ./convert.sh, chmod + x, e quindi reindirizzare l'input in modo che stamperà l'output? Sto ottenendo un errore: /usr/bin/awk: syntax error at source line 1 context is >>> . <<< /convert.sh.
Cwd

@cwd Puoi salvarlo in un file, suggerirei convert.awkdi indicare che è uno awkscript e non bashuno. Ho aggiornato il post con l'intera riga di comando e ho notato che ho aggiunto un -fflag che avevo dimenticato nella prima riga (che gli dice di interpretare il file come comandi).
Kevin,

La versione one-liner considera qualsiasi spazio bianco come un separatore di campo, non solo schede. Ha bisogno di -F '\ t' prima di -V.
Paul_Pedant,

4

Ecco una soluzione perl. Questo potrebbe essere possibile con sed / awk, ma il test per la parte numerica probabilmente lo renderebbe piuttosto brutto.

ec2-describe-snapshots -H --hide-tags | \
perl -e 'use Scalar::Util qw(looks_like_number);
         while (chomp($line = <STDIN>)) {
             print(join(",", map { "\"" . (looks_like_number($_) ? "=$_" :
                                           do {s/"/""/g; $_}) . "\"" }
             split(/\t/, $line)) . "\n");
         }' \
> snapshots.csv

3

Se sei solo pigro come me e vuoi fare tutto su una riga di comando senza scrivere uno script, ecco come lo farei.

ec2-describe-snapshots -H --hide-tags | sed -e 's/^I/","/g' | sed -e 's/^/"/' | sed -e 's/$/"/'> snapshots.csv

La ^Isi effettua premendo ctrl+ v i.

I primi sedscambi tutto tabsper ",". Il secondo sedinserisce "a all'inizio di ogni riga e l'ultimo sed inserisce una chiusura "alla fine di ogni riga.


Come hai ottenuto che ctrl + vi si presentasse così?
Burhan Khalid,

@burhan La sintassi è <kbd>text</kbd>.
jw013,

3
O in una riga: sed -e 's/^I/","/g' -e 's/.*/"&"/'o anche più breve sed -e 's/^I/","/g;s/.*/"&"/'.
Arcege,

3

Un'altra soluzione Perl:

#!/usr/bin/perl -wln
use strict;

my($n,$s);chomp();
for $s ( split(/\t/,$_) )
{
    $s = '='.$s if ($s =~ /^\d+$/);
    $n.= '"'.$s.'",';
}
$n =~ s/(.*),/$1/;print $n;

invocare con ec2-describe-snapshots -H --hide-tags | /var/tmp/script.pl > output.txt


Scalar :: Util non è un modulo esterno, viene fornito con perl standard.
Patrick,

Vero. Chiedo scusa per aver espresso male il mio commento previsto. Grazie per la correzione.
Jim,

1

sed è l'utilità linux più utile che abbia mai incontrato.

sed 's/\t/","/g' TabSeparatedValues.txt > CommaSeparatedValues.csv
sed -i 's/.*/"&"/' CommaSeparatedValues.csv

Il primo comando sostituisce tutte le schede in ogni riga con virgole e virgolette. Il secondo comando inserisce le virgolette all'inizio e alla fine di ogni riga, in modo che ciascun valore sia racchiuso tra virgolette, il che consente alle virgole di far parte del valore.


0

Questo potrebbe funzionare per te:

sed 's/\t\+/,/g;s/^\|$/"/g;s/,/"&"/g;s/"\([0-9]\+\)"/"=\1"/g' file
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.