So teilen Sie eine Datei mithilfe von Schlüsselwortgrenzen

14

Ich habe eine vcf-Datei, die zahlreiche vcards enthält.

Beim Importieren der vcf-Datei in Outlook wird anscheinend nur die erste vcard importiert.

Daher möchte ich sie aufteilen.

Vorausgesetzt, eine vcard beginnt mit

BEGIN:VCARD

und endet mit

END:VCARD

Was ist der beste Weg, um jede vCard in eine eigene Datei aufzuteilen.

Vielen Dank

AKTUALISIEREN

Vielen Dank für alle Antworten. Wie bei Fragen dieser Art gibt es verschiedene Möglichkeiten, eine Katze zu häuten. Hier ist die Begründung, warum ich die gewählt habe, die ich getan habe.

ZUSAMMENFASSEN

Hier ist eine Zusammenfassung dessen, was mir aus jeder Antwort gefallen hat und was mich dazu bewogen hat, eine davon auszuwählen.

  • csplit: Ich mochte die Prägnanz dieser Methode wirklich sehr. Ich wünschte nur, es könnte auch die Dateierweiterung setzen.
  • gawk: Es hat alles getan, was ich verlangt habe.
  • paralell: Hat funktioniert. Aber ich musste neue Dinge installieren. (Es wurde auch beschlossen, ein neues / bin-Verzeichnis in meinem Heimatverzeichnis zu erstellen.)
  • perl: Es hat mir gefallen, dass vcf basierend auf dem Namen des Kontakts erstellt wurde. Aber die Option -o hat nicht wirklich funktioniert

Fazit

  • Also war der erste, der ging, perlweil es ein bisschen kaputt war
  • Als nächstes paralellmusste ich neue Dinge installieren
  • Als nächstes kam csplit, soweit ich sehen kann, keine Erweiterungen für die Ausgabedateien
  • Die Auszeichnung geht an gawk, weil es sich um ein Dienstprogramm handelt, das leicht verfügbar und vielseitig genug ist, um den Dateinamen ein wenig zu hacken und zu ändern. Bonuspunkte für cmpauch :)
Denormalisierer
quelle
Hast du versucht mit -b?
Ignacio Vazquez-Abrams

Antworten:

11

Sie können awk für den Job verwenden:

$ curl -O https://raw.githubusercontent.com/qtproject/qt-mobility\
/d7f10927176b8c3603efaaceb721b00af5e8605b/demos/qmlcontacts/contents/\
example.vcf

$ gawk ' /BEGIN:VCARD/ { close(fn); ++a; fn=sprintf("card_%02d.vcf", a); 
        print "Writing: ", fn } { print $0 > fn; } ' example.vcf
Writing:  card_01.vcf
Writing:  card_02.vcf
Writing:  card_03.vcf
Writing:  card_04.vcf
Writing:  card_05.vcf
Writing:  card_06.vcf
Writing:  card_07.vcf
Writing:  card_08.vcf
Writing:  card_09.vcf

$ cat card_0* > all.vcf
$ cmp example.vcf all.vcf
$ echo $?
0

Einzelheiten

Die awk-Zeile funktioniert folgendermaßen: aist ein Zähler, der in jeder BEGIN:VCARDZeile erhöht wird , und gleichzeitig wird der Ausgabedateiname mit sprintf (gespeichert in fn) erstellt. Für jede Zeile wird die aktuelle Zeile ( $0) an die aktuelle Datei (benannt fn) angehängt .

Letzteres echo $?bedeutet, dass das cmperfolgreich war, dh alle verketteten Einzeldateien entsprechen dem ursprünglichen Beispiel vcf example.

Beachten Sie, dass die Ausgabeumleitung in awk anders funktioniert als in shell. Das bedeutet, dass mit > fnawk zunächst geprüft wird, ob die Datei bereits geöffnet ist. Wenn es bereits geöffnet ist, hängt awk daran an . Ist dies nicht der Fall, wird es geöffnet und abgeschnitten.

Aufgrund dieser Umleitungslogik müssen wir die implizit geöffneten Dateien explizit schließen , da andernfalls der Aufruf in Fällen, in denen die Eingabedatei viele Datensätze enthält, die Obergrenze für geöffnete Dateien überschreiten würde.

maxschlepzig
quelle
Sie müssen die Datei schließen, um zu vermeiden, dass in awk zu viele Dateien geöffnet werden. stackoverflow.com/questions/32878146/… Der Befehl lautet also: gawk '/ BEGIN: VCARD / {close (fn); ++ a; fn = sprintf ("card_% 02d.vcf", a); print "Writing:", fn} {print $ 0 >> fn; } 'example.vcf
Dan Bennett
@DanBennett Vielen Dank für den Hinweis! Ich habe meine Antwort aktualisiert und auch die Umleitungslogik / Hinweise zur festen Umleitung vereinfacht.
Maxschlepzig
11
csplit -f vcard input.txt -z '/END:VCARD/+1' '{*}'
Ignacio Vazquez-Abrams
quelle
5

Die Gnu-Version von csplit kann die Erweiterung festlegen - Ignacios Antwort ist meines Erachtens die prägnanteste. Sie benötigt nur die letzte Feinabstimmung, um die Erweiterung zu erhalten - unter Verwendung des 'printf'-Formats:

csplit -f vcard -b %02d.vcard input.txt -z '/END:VCARD/+1' '{*}'

Hier ist der relevante Ausschnitt aus der Gnu- csplitManpage:

   -b, --suffix-format=FORMAT
          use sprintf FORMAT instead of %02d
Keithel
quelle
Ich habe einen Mac verwendet und es hat eine Weile gedauert, bis ich herausgefunden habe, ob ich stattdessen gcsplit verwende. Aber als ich das getan habe, hat mir diese Antwort geholfen.
Luke Gedeon
4

Mit diesem Skript können Sie die Arbeit erledigen. Es heißt split-vcf-Datei .

Anwendungsbeispiel

$ split_vcf.pl 

Error! Input VCF filename missing,  -i

Usage: perl split_vcf.pl -i input_file -o output_dir [OPTION]

    -v,         Verbosity levels, 1-3

So führen Sie das Skript aus:

mkdir vcf_files
split_vcf.pl  -i current.vcf -o vcf_files
slm
quelle
split_vcf.pl ist eine Windows-Version. für unix ändere den sub make_filename der ein "\" in den dateinamen hinzufügte.
J Dan
4

Mit GNU Parallel können Sie:

cat foo.vcf | parallel --pipe -N1 --recstart BEGIN:VCARD 'cat >{#}'

Oder wenn Sie http://oletange.blogspot.com/2013/10/useless-use-of-cat.html widerlegen können, können Sie dies stattdessen verwenden:

< foo.vcf parallel --pipe -N1 --recstart BEGIN:VCARD 'cat >{#}'

Weitere Beispiele finden Sie unter: http://www.gnu.org/software/parallel/man.html

Sehen Sie sich die Intro-Videos an: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

10 Sekunden Installation:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 3374ec53bacb199b245af2dda86df6c9
12345678 3374ec53 bacb199b 245af2dd a86df6c9
$ md5sum install.sh | grep 029a9ac06e8b5bc6052eac57b2c3c9ca
029a9ac0 6e8b5bc6 052eac57 b2c3c9ca
$ sha512sum install.sh | grep f517006d9897747bed8a4694b1acba1b
40f53af6 9e20dae5 713ba06c f517006d 9897747b ed8a4694 b1acba1b 1464beb4
60055629 3f2356f3 3e9c4e3c 76e3f3af a9db4b32 bd33322b 975696fc e6b23cfb
$ bash install.sh
Ole Tange
quelle