Cómo dividir un archivo usando límites de palabras clave

15

Tengo un archivo vcf que contiene numerosas vcards.

Al importar el archivo vcf a Outlook, parece importar solo la primera vcard.

Por lo tanto, quiero dividirlos.

Dado que una vcard comienza con

BEGIN:VCARD

y termina con

END:VCARD

¿Cuál es la mejor manera de dividir cada vcard en su propio archivo?

Gracias

ACTUALIZAR

Gracias por todas las respuestas. Al igual que con las preguntas de esta naturaleza, hay varias formas de desollar a un gato. Aquí está el razonamiento por el que elegí el que hice.

REDONDEO

Aquí hay un resumen de lo que me gustó de cada respuesta y lo que me llevó a seleccionar una de ellas.

  • csplit: Realmente me gustó la concisión de este método. Solo deseaba poder establecer también la extensión del archivo.
  • gawk: Hizo todo lo que le pedí.
  • paralell: Trabajó. Pero tuve que instalar cosas nuevas. (también decidió hacer un nuevo directorio / bin en mi directorio de inicio)
  • perl: Me gustó que creara vcf en función del nombre del contacto. Pero la opción -o realmente no funcionó

Conclusión

  • Así que el primero en irse fue perlporque estaba un poco roto
  • Lo siguiente fue paralellporque tuve que instalar cosas nuevas
  • El siguiente fue csplit, porque hasta donde puedo ver, no puede crear extensiones en los archivos de salida
  • Entonces, el premio es para gawk, por ser una utilidad fácilmente disponible y lo suficientemente versátil que puedo cortar y cambiar un poco el nombre del archivo. Marcas de bonificación para cmptambién :)
desnormalizador
fuente
¿Intentaste usar -b?
Ignacio Vazquez-Abrams

Respuestas:

11

Puedes usar awk para el trabajo:

$ 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

Detalles

La línea awk funciona así: aes un contador que se incrementa en cada BEGIN:VCARDlínea y al mismo tiempo el nombre del archivo de salida se construye usando sprintf (almacenado en fn). Para cada línea, la línea actual ( $0) se agrega al archivo actual (denominado fn).

El último echo $?significa que cmpfue exitoso, es decir, todos los archivos individuales concatenados son iguales al ejemplo original vcf.

Tenga en cuenta que la redirección de salida en awk funciona de manera diferente que en shell. Eso significa que con > fnawk primero verifica si el archivo ya está abierto. Si ya está abierto, entonces awk se agrega a él . Si no es así, se abre y lo trunca.

Debido a esta lógica de redireccionamiento, tenemos que cerrar explícitamente los archivos abiertos implícitamente, ya que de lo contrario la llamada alcanzaría el límite de archivos abiertos en los casos en que el archivo de entrada contiene muchos registros.

maxschlepzig
fuente
Deberá cerrar el archivo para evitar un error de demasiados archivos abiertos en awk. stackoverflow.com/questions/32878146/… Entonces el comando se convierte en: gawk '/ BEGIN: VCARD / {close (fn); ++ a; fn = sprintf ("tarjeta_% 02d.vcf", a); print "Writing:", fn} {print $ 0 >> fn; } 'example.vcf
Dan Bennett
@DanBennett ¡Muchas gracias por la pista! He actualizado mi respuesta y también simplifiqué la lógica de redireccionamiento / notas relacionadas con la redirección fija.
maxschlepzig
11
csplit -f vcard input.txt -z '/END:VCARD/+1' '{*}'
Ignacio Vazquez-Abrams
fuente
5

La versión Gnu de csplit puede establecer la extensión; creo que la respuesta de Ignacio es la más concisa, solo necesita ese último ajuste para obtener la extensión, usando el formato 'printf':

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

Aquí está el fragmento relevante de la csplitpágina de manual de gnu :

   -b, --suffix-format=FORMAT
          use sprintf FORMAT instead of %02d
Keithel
fuente
Estaba usando mac y me tomó un tiempo darme cuenta de que usaba gcsplit, pero una vez que lo hice, esta respuesta me ayudó.
Luke Gedeon
4

Puede usar este script para hacer el trabajo. Se llama split-vcf-file .

Ejemplo de uso

$ 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

Para ejecutar el script:

mkdir vcf_files
split_vcf.pl  -i current.vcf -o vcf_files
slm
fuente
split_vcf.pl es una versión de windows. para Unix, modifique el sub make_filename que estaba agregando una "\" en los nombres de archivo.
J Dan
4

Usando GNU Parallel puedes hacer:

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

O si puede refutar http://oletange.blogspot.com/2013/10/useless-use-of-cat.html , puede usar esto en su lugar:

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

Ver más ejemplos: http://www.gnu.org/software/parallel/man.html

Mira los videos de introducción: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Instalación de 10 segundos:

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