Wie kann ich tabulatorgetrennte Daten in durch Kommas getrennte Daten konvertieren?

8

Ich fordere eine Liste von ec2-Snapshots über das ec2-Befehlszeilentool von amazon an:

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

Die Daten sehen ungefähr so ​​aus:

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

Wie kann ich die Daten abfangen, bevor ich sie umleitung, snapshots.csvund die folgenden Schritte ausführen:

  • Ersetzen Sie "Tabulatoren" durch Kommas
  • Werte in Anführungszeichen setzen
  • Wenn ein Wert nur aus Zahlen besteht, stellen Sie ihm ein Präfix =voran, damit Excel ihn als Text behandelt - zum Beispiel OwnerIdsollte er "=5098939"sein (dieser ist nicht erforderlich, wenn er nicht inline ausgeführt werden kann und stattdessen eine Skriptdatei oder -funktion erfordert).

gewünschte Ausgabe:

"SnapshotId","VolumeId","StartTime","OwnerId","VolumeSize","Description"
"snap-00b66464","vol-b99a38d0","2012-01-05","=5098939","=160","my backup"
cwd
quelle
Hier fordert Sie jemand auf, mithilfe von Registerkarten zu importieren. Oder sie würden es tun, wenn Excel nicht auf dem Sprung wäre.
Ignacio Vazquez-Abrams
Ja, ich versuche, ein bisschen besser zu werden, da es von sich aus nicht so heiß zu sein scheint. Es ist auch immer schön, eine CSV-Datei zu haben, die einfach geöffnet werden kann, anstatt den Befehl zum Importieren des Menüs verwenden zu müssen. Ich habe bereits versucht, die Erweiterung ohne Glück auf ".tsv" zu ändern.
CWD
Ich denke, Ihre gewünschte Ausgabe ist ein bisschen aus. Sie haben dort viele leere Felder (die leeren Anführungszeichen).
Patrick

Antworten:

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
}

Angenommen, Sie nennen dies convert.awk, können Sie entweder mit beiden anrufen

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

oder (nach dem Hinzufügen von Ausführungsberechtigungen chmod a+x convert.awk)

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

Dadurch wird für jede Registerkarte eine neue Spalte erstellt, die die Kommentarspalte zusammenhält (es sei denn, sie enthält Registerkarten), aber leere Spalten hinzufügt (obwohl Ihre Beispielausgabe so aussieht, möchten Sie das vielleicht tatsächlich). Wenn Sie alle Leerzeichen aufteilen möchten (dadurch werden zusätzliche Registerkarten in der Tabelle reduziert, aber jedes Wort in der Beschreibung als neue Spalte eingefügt), entfernen Sie die FS="\t";Anweisung.

Wenn Sie für zukünftige Generationen kein "s oder =s oder eingebettetes Leerzeichen benötigen , können Sie es zu einem Einzeiler machen:

awk -v OFS=, '{$1=$1;print}'
Kevin
quelle
Schöne saubere Lösung. Ich dachte, es würde viel hässlicher enden, aber dann bin ich kein schlechter Mensch :-)
Patrick
speichere ich dies in einer Datei wie ./convert.shchmod + x und leite dann die Eingabe hinein, damit die Ausgabe gedruckt wird? Ich erhalte eine Fehlermeldung : /usr/bin/awk: syntax error at source line 1 context is >>> . <<< /convert.sh.
CWD
@cwd Sie können es in einer Datei speichern. Ich würde vorschlagen convert.awk, dass es sich um ein awkSkript handelt und nicht um ein Skript bash. Ich habe den Beitrag mit der vollständigen Befehlszeile aktualisiert und festgestellt, dass ich -fder ersten Zeile ein Flag hinzugefügt habe, das ich vergessen habe (das besagt, dass die Datei als Befehle interpretiert werden soll).
Kevin
In der einzeiligen Version werden Leerzeichen als Feldtrennzeichen behandelt, nicht nur Tabulatoren. Benötigt ein -F '\ t' vor dem -V.
Paul_Pedant
4

Hier ist eine Perl-Lösung. Dies könnte mit sed / awk möglich sein, aber das Testen des numerischen Teils würde es wahrscheinlich ziemlich hässlich machen.

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
Patrick
quelle
3

Wenn Sie nur faul wie ich sind und alles in einer Befehlszeile ausführen möchten, ohne ein Skript zu schreiben, würde ich das folgendermaßen tun.

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

Das ^Iwird durch Drücken von ctrl+ gemacht v i.

Der erste sedtauscht alles tabsgegen ",". Der zweite sedfügt "am Anfang jeder Zeile ein ein, und der letzte sed fügt "am Ende jeder Zeile einen Abschluss ein .

Tim Kennedy
quelle
Wie bist du dazu gekommen, dass Strg + vi so angezeigt wird?
Burhan Khalid
@burhan Die Syntax ist <kbd>text</kbd>.
jw013
3
Oder in einer Zeile: sed -e 's/^I/","/g' -e 's/.*/"&"/'oder noch kürzer sed -e 's/^I/","/g;s/.*/"&"/'.
Arcege
3

Eine weitere Perl-Lösung:

#!/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;

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

Jim
quelle
Scalar :: Util ist kein externes Modul, sondern wird mit Standard-Perl geliefert.
Patrick
Wahr. Entschuldigung für die schlechte Formulierung meines beabsichtigten Kommentars. Danke für die Verbesserung.
Jim
1

sed ist das nützlichste Linux-Dienstprogramm, das mir je begegnet ist.

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

Der erste Befehl ersetzt alle Registerkarten in jeder Zeile durch Kommas und Anführungszeichen. Der zweite Befehl fügt am Anfang und am Ende jeder Zeile Anführungszeichen ein, sodass jeder Wert in Anführungszeichen gesetzt wird, sodass Kommas Teil des Werts sein können.

Paul
quelle
0

Dies könnte für Sie funktionieren:

sed 's/\t\+/,/g;s/^\|$/"/g;s/,/"&"/g;s/"\([0-9]\+\)"/"=\1"/g' file
Potong
quelle