
gdriveverfügt über einen Unterbefehl list
, der eine Liste von Dateien wie im folgenden Beispiel druckt:
gdrive list
Ausgabe:
Id Name Type Size Created
1sV3_a1ySV0-jbLxhA8NIEts1KU_aWa-5 info.pdf bin 10.0 B 2018-08-27 20:26:20
1h-j3B5OLryp6HkeyTsd9PJaAtKK_GYyl 2018-12-ss-scalettapass dir 2018-08-27 20:26:19
Ich versuche, diese Ausgabe mit Tools wie awk
und zu analysieren, sed
ohne Erfolg.
Die Probleme sind leere „Felder“ in der Größenspalte und die dynamische Breite der Spalten.
Hat jemand eine Idee, wie diese Ausgabe analysiert werden kann?
Antwort1
awk kann mit Daten fester Breite umgehen. Zuerst müssen wir die Spaltenbreiten bestimmen:
fieldwidths=$(head -n 1 file | grep -Po '\S+\s*' | awk '{printf "%d ", length($0)}')
Dieser Wert ist "36 26 7 9 7 "
– das letzte Feld ist länger als 7 Zeichen. Lassen Sie uns daraus beliebig 70 Zeichen machen:
fieldwidths=${fieldwidths/% /0}
Lassen Sie uns nun die Daten lesen und in CSV umwandeln:
awk -v FIELDWIDTHS="$fieldwidths" '{
for (i=1; i<=NF; i++) {
val = $i
sub(/ *$/, "", val)
gsub(/"/, "\"\"", val)
printf "%s\"%s\"", (i==1 ? "" : ","), val
}
print ""
}' file
Ausgänge:
"Id","Name","Type","Size","Created"
"1sV3_a1ySV0-jbLxhA8NIEts1KU_aWa-5","info.pdf","bin","10.0 B","2018-08-27 20:26:20"
"1h-j3B5OLryp6HkeyTsd9PJaAtKK_GYyl","2018-12-ss-scalettapass","dir","","2018-08-27 20:26:19"
Dieselbe Funktionalität mit Perl
perl -lne '
if ($. == 1) {
@head = ( /(\S+\s*)/g );
pop @head;
$patt = "^";
$patt .= "(.{" . length($_) . "})" for @head;
$patt .= "(.*)\$";
}
print join ",", map {s/"/""/g; s/\s+$//; qq("$_")} (/$patt/o);
' file
Antwort2
Dies gelingt Ihnen mit Perl
der unpack
Funktion, indem Sie die Entpackvorlage dynamisch durch Untersuchung des Headers (1. Zeile) erstellen:
perl -lpe '
$fmt //= join "", map("A" . length(), /\H+\h+(?=\H)/g), "A*";
$_ = join ",", map { s/"/""/gr =~ s/(.*)/"$1"/r } unpack $fmt;
' input-file.txt
Erläuterung:
-p
wirdperl
die Datei zeilenweise nutzen. Jede Zeile, auch Datensatz genannt, wird als bezeichnet$_
. Ein weiterer Effekt von-p
ist, dass der aktuelle Datensatz automatisch gedruckt wird, bevor der nächste abgerufen wird.-l
macht 2 Dinge, setztORS = RS = \n
- Der reguläre Ausdruck
/\H+\h+(?=\H)/g
soll alle Felder außer dem letzten abrufen und diese dann an weiterleitenmap
. map
berechnet die Längen dieser Felder und stellt jedem ein „A“ voran.- Anstatt das letzte Feld oben nicht auszuwählen, fügen wir einen Sammelbegriff „A*“ hinzu.
- Diese werden dann an übergeben,
join
das sie mit dem Null-Trennzeichen zu einem String zusammenfügt. Damit ist das Entpackformat einsatzbereit und muss aufgrund des//=
Operators, der diedefined-or
Funktion darstellt, nicht erneut berechnet werden. - Nun können wir, ausgerüstet mit dem dynamisch erstellten Entpackformat, mit der Anwendung auf jede Zeile fortfahren, einschließlich der Kopfzeile.
unpack
entpackt einen String, in unserem Fall die aktuelle Zeile, im bereitgestellten Format und gibt entpackte Felder aus.- Diese ausgegebenen Felder werden dann als Eingabe verwendet. Das
map
Programm bearbeitet sie nacheinander und führt die im{ ... }
Code beschriebenen Schritte aus. In unserem Fall machen wir in jedem Feld Folgendes: a) Verdoppeln Sie die Anführungszeichen. b) Versehen Sie das Feld mit Anführungszeichen. - Nachdem
map
die Bearbeitung der Felder abgeschlossen ist, werden sie an übergebenjoin
, das sie mithilfe von Kommas,
zu einer hübschen kleinenCSV
Datei zusammenfügt. - PS:Beachten Sie, dass wir die nachstehenden Leerzeichen in den von generierten Feldern nicht entfernen mussten
unpack
, daunpack
dies bei Verwendung desA
Formatierungszeichens (A für ASCII) für Sie erledigt wird.
Ausgabe:
"Id","Name","Type","Size","Created"
"1sV3_a1ySV0-jbLxhA8NIEts1KU_aWa-5","info.pdf","bin","10.0 B","2018-08-27 20:26:20"
"1h-j3B5OLryp6HkeyTsd9PJaAtKK_GYyl","2018-12-ss-scalettapass","dir","","2018-08-27 20:26:19"
Dies kann vom sed
Tool durchgeführt werden, erfordert aber einen zweistufigen Ansatz. Dabei generieren wir zunächst mithilfe der Kopfzeile der Eingabe sed
dynamisch ein Skript, das dann die Eingabedatei (einschließlich der Kopfzeile) verarbeitet, um die gewünschte Operation auszuführen, wie gezeigt:
if="input-file.txt"
cmd=$(< "$if" head -n 1 | perl -lne 'print join $/, reverse map { $s += length();qq[s/./\\n/$s] } /\H+\h+(?=\H)/g')
sed -e '
'"${cmd}"'
s/"/""/g
s/[[:blank:]]*\n/","/g
s/.*/"&"/
' < "$if"