Come dividere un file usando i limiti delle parole chiave


15

Ho un file vcf che contiene numerose vcard.

Quando si importa il file vcf in Outlook sembra importare solo la prima vcard.

Quindi voglio dividerli.

Dato che una vcard inizia con

BEGIN:VCARD

e termina con

END:VCARD

Qual è il modo migliore per dividere ogni vcard nel suo file.

Grazie

AGGIORNARE

Grazie per tutte le risposte. Come per le domande di questo tipo, esistono vari modi per scuoiare un gatto. Ecco il ragionamento per cui ho scelto quello che ho fatto.

ARROTONDARE

Ecco una carrellata di ciò che mi è piaciuto di ogni risposta e di ciò che mi ha spinto a selezionarne uno.

  • csplit: Mi è davvero piaciuta la concisione di questo metodo. Ho solo desiderato poter impostare anche l'estensione del file.
  • gawk: Ha fatto tutto ciò che gli ho chiesto.
  • paralell: Lavorato. Ma ho dovuto installare nuove cose. (ha anche deciso di creare una nuova directory / bin nella mia home directory)
  • perl: Mi è piaciuto che ha creato vcf in base al nome del contatto. Ma l'opzione -o non ha funzionato davvero

Conclusione

  • Quindi il primo ad andare è stato perlperché era un po 'rotto
  • Il prossimo è stato paralellperché dovevo installare nuove cose
  • Il prossimo è stato csplit, perché per quanto posso vedere non è possibile creare estensioni sui file di output
  • Quindi il premio va a gawk, per essere un'utilità che è prontamente disponibile e abbastanza versatile da poter tagliare e cambiare un po 'il nome del file. Segni bonus cmpanche per :)

Hai provato a usare -b?
Ignacio Vazquez-Abrams,

Risposte:


11

Puoi usare awk per il lavoro:

$ 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

Dettagli

La riga awk funziona in questo modo: aè un contatore che viene incrementato su ogni BEGIN:VCARDriga e allo stesso tempo il nome del file di output viene costruito usando sprintf (memorizzato in fn). Per ogni riga la riga corrente ( $0) viene aggiunta al file corrente (denominato fn).

L'ultimo echo $?indica che l'operazione ha cmpavuto esito positivo, vale a dire che tutti i singoli file concatenati sono uguali all'esempio originale vcf.

Si noti che il reindirizzamento dell'output in awk funziona in modo diverso rispetto alla shell. Ciò significa che con > fnawk prima controlla se il file è già aperto. Se è già aperto, Awk lo aggiunge . Se non lo è, si apre e lo tronca.

A causa di questa logica di reindirizzamento dobbiamo chiudere esplicitamente i file aperti implicitamente, poiché altrimenti la chiamata colpirà il limite del file aperto nei casi in cui il file di input contiene molti record.


Dovrai chiudere il file per evitare un errore di troppi file aperti in awk. stackoverflow.com/questions/32878146/… Quindi il comando diventa: gawk '/ BEGIN: VCARD / {close (fn); ++ a; fn = sprintf ("card_% 02d.vcf", a); print "Writing:", fn} {stampa $ 0 >> fn; } 'example.vcf
Dan Bennett,

@DanBennett Grazie mille per il suggerimento! Ho aggiornato la mia risposta e anche semplificato la logica di reindirizzamento / note relative al reindirizzamento fisso.
maxschlepzig,


5

La versione Gnu di csplit può impostare l'estensione - la risposta di Ignacio penso sia la più concisa, ha solo bisogno di quell'ultima modifica per ottenere l'estensione - usando il formato 'printf':

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

Ecco lo snippet pertinente dalla csplitpagina man di gnu :

   -b, --suffix-format=FORMAT
          use sprintf FORMAT instead of %02d

Stavo usando Mac e mi ci è voluto un po 'di tempo per capire di usare gcsplit, ma una volta ho fatto questa risposta mi ha aiutato.
Luke Gedeon,

4

Puoi usare questo script per fare il lavoro. Si chiama split-vcf-file .

Esempio di utilizzo

$ 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

Per eseguire lo script:

mkdir vcf_files
split_vcf.pl  -i current.vcf -o vcf_files

split_vcf.pl è una versione di Windows. per unix modificare il sub make_filename che stava aggiungendo un "\" nei nomi dei file.
J Dan,

4

Usando GNU Parallel puoi fare:

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

Oppure, se puoi rifiutare http://oletange.blogspot.com/2013/10/useless-use-of-cat.html puoi invece usare questo:

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

Vedi altri esempi: http://www.gnu.org/software/parallel/man.html

Guarda i video introduttivi: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

10 secondi di installazione:

$ (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
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.