Como dividir um arquivo usando limites de palavras-chave

14

Eu tenho um arquivo vcf que contém vários cartões postais.

Ao importar o arquivo vcf para o Outlook, parece importar apenas o primeiro vcard.

Por isso, quero dividi-los.

Dado que um vcard começa com

BEGIN:VCARD

e termina com

END:VCARD

Qual é a melhor maneira de dividir cada vcard em seu próprio arquivo.

obrigado

ATUALIZAR

Obrigado por todas as respostas. Tal como acontece com questões desta natureza, existem várias maneiras de esfolar um gato. Aqui está o raciocínio pelo qual escolhi o que fiz.

ARREDONDAR PARA CIMA

Aqui está um resumo do que eu gostei em cada resposta e o que me levou a selecionar uma delas.

  • csplit: Eu realmente gostei da concisão desse método. Eu só queria que também fosse possível definir a extensão do arquivo.
  • gawk: Fez tudo o que eu pedi.
  • paralell: Trabalhou. Mas eu tive que instalar coisas novas. (também decidiu criar um novo diretório / bin no meu diretório doméstico)
  • perl: Gostei que ele criou vcf com base no nome do contato. Mas a opção -o realmente não funcionou

Conclusão

  • Então o primeiro a ir foi perlporque estava um pouco quebrado
  • Em seguida foi paralellporque eu tive que instalar coisas novas
  • Em seguida csplit, porque, tanto quanto eu posso ver, não é possível criar extensões nos arquivos de saída
  • Portanto, o prêmio vai para o gawk, por ser um utilitário prontamente disponível e versátil o suficiente para que eu possa cortar e alterar um pouco o nome do arquivo. Marcas de bônus para cmptambém :)
desnormalizador
fonte
Você tentou usar -b?
Ignacio Vazquez-Abrams

Respostas:

11

Você pode usar o awk para o trabalho:

$ 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

Detalhes

A linha awk funciona assim: aé um contador incrementado em cada BEGIN:VCARDlinha e, ao mesmo tempo, o nome do arquivo de saída é construído usando o sprintf (armazenado em fn). Para cada linha, a linha atual ( $0) é anexada ao arquivo atual (nomeado fn).

O último echo $?significa que o cmparquivo foi bem-sucedido, ou seja, todos os arquivos únicos concatenados são iguais ao exemplo original exemplo vcf.

Observe que o redirecionamento de saída no awk funciona de maneira diferente do que no shell. Isso significa que, com o > fnawk, primeiro verifica se o arquivo já está aberto. Se já estiver aberto, o awk será anexado a ele . Caso contrário, ele será aberto e truncado.

Devido a essa lógica de redirecionamento, precisamos fechar explicitamente os arquivos abertos implicitamente, pois, caso contrário, a chamada atingiria o limite de arquivos abertos nos casos em que o arquivo de entrada contenha muitos registros.

maxschlepzig
fonte
Você precisará fechar o arquivo para evitar um erro de muitos arquivos abertos no awk. stackoverflow.com/questions/32878146/… Portanto, o comando se torna: gawk '/ BEGIN: VCARD / {close (fn); ++ a; fn = sprintf ("cartão_% 02d.vcf", a); print "Escrita:", fn} {print $ 0 >> fn; } 'example.vcf
Dan Bennett
@ DanBennett Muito obrigado pela dica! Atualizei minha resposta e também simplifiquei as notas relacionadas à lógica de redirecionamento / redirecionamento fixo.
maxschlepzig
11
csplit -f vcard input.txt -z '/END:VCARD/+1' '{*}'
Ignacio Vazquez-Abrams
fonte
5

A versão Gnu do csplit pode definir a extensão - a resposta de Ignacio, eu acho a mais concisa, só precisa do último pedaço de ajustes para obter a extensão - usando o formato 'printf':

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

Aqui está o trecho relevante da csplitpágina de manual do gnu :

   -b, --suffix-format=FORMAT
          use sprintf FORMAT instead of %02d
Keithel
fonte
Eu estava usando mac e demorei um pouco para descobrir o uso do gcsplit, mas uma vez que fiz essa resposta, me ajudou.
Luke Gedeon
4

Você pode usar esse script para fazer o trabalho. É chamado split-vcf-file .

Exemplo 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 executar o script:

mkdir vcf_files
split_vcf.pl  -i current.vcf -o vcf_files
slm
fonte
split_vcf.pl é uma versão do Windows. para unix, modifique o sub make_filename que estava adicionando um "\" nos nomes dos arquivos.
J Dan
4

Usando o GNU Parallel, você pode:

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

Ou, se você puder refutar http://oletange.blogspot.com/2013/10/useless-use-of-cat.html, poderá usar isso:

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

Veja mais exemplos: http://www.gnu.org/software/parallel/man.html

Assista aos vídeos de introdução: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

10 segundos de instalação:

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