Comment diviser un fichier en utilisant les limites des mots clés

15

J'ai un fichier vcf qui contient de nombreuses vcards.

Lors de l'importation du fichier vcf dans Outlook, il semble que seule la première vcard soit importée.

C'est pourquoi je veux les diviser.

Étant donné qu'une vcard commence par

BEGIN:VCARD

et se termine par

END:VCARD

Quelle est la meilleure façon de diviser chaque vcard en son propre fichier.

Merci

MISE À JOUR

Merci pour toutes les réponses. Comme pour les questions de cette nature, il existe différentes façons d'écorcher un chat. Voici le raisonnement pour lequel j'ai choisi celui que j'ai fait.

ARRONDISSEMENT

Voici un résumé de ce que j'ai aimé dans chaque réponse et ce qui m'a poussé à en sélectionner une.

  • csplit: J'ai vraiment beaucoup aimé la concision de cette méthode. Je souhaitais juste qu'il puisse également définir l'extension de fichier.
  • gawk: Il a fait tout ce que je lui ai demandé.
  • paralell: Travaillé. Mais j'ai dû installer de nouvelles choses. (il a également décidé de créer un nouveau répertoire / bin dans mon répertoire personnel)
  • perl: J'ai aimé qu'il ait créé vcf basé sur le nom du contact. Mais l'option -o n'a pas vraiment fonctionné

Conclusion

  • Donc, le premier à aller était perlparce qu'il était un peu cassé
  • Ensuite, paralellparce que je devais installer de nouvelles choses
  • Ensuite csplit, car pour autant que je puisse voir, il ne peut pas créer d'extensions sur les fichiers de sortie
  • Le prix revient donc à gawk, pour être un utilitaire facilement disponible et suffisamment polyvalent pour que je puisse hacher et changer un peu le nom du fichier. Des points bonus cmpaussi :)
dénormaliseur
la source
Avez-vous essayé d'utiliser -b?
Ignacio Vazquez-Abrams

Réponses:

11

Vous pouvez utiliser awk pour le travail:

$ 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

Détails

La ligne awk fonctionne comme ceci: ac'est un compteur qui est incrémenté sur chaque BEGIN:VCARDligne et en même temps le nom du fichier de sortie est construit en utilisant sprintf (stocké dans fn). Pour chaque ligne, la ligne actuelle ( $0) est ajoutée au fichier actuel (nommé fn).

Le dernier echo $?signifie que l'opération cmpa réussi, c'est-à-dire que tous les fichiers uniques concaténés sont égaux à l'exemple vcf de l'exemple d'origine.

Notez que la redirection de sortie dans awk fonctionne différemment que dans shell. Cela signifie qu'avec > fnawk vérifie d'abord si le fichier est déjà ouvert. S'il est déjà ouvert, awk s'y ajoute . Si ce n'est pas le cas, il s'ouvre et le tronque.

En raison de cette logique de redirection, nous devons fermer explicitement les fichiers ouverts implicitement, car sinon l'appel atteindrait la limite de fichier ouvert dans les cas où le fichier d'entrée contient de nombreux enregistrements.

maxschlepzig
la source
Vous devrez fermer le fichier pour éviter une trop grande erreur de fichiers ouverts dans awk. stackoverflow.com/questions/32878146/… La commande devient donc: gawk '/ BEGIN: VCARD / {close (fn); ++ a; fn = sprintf ("card_% 02d.vcf", a); print "Writing:", fn} {print $ 0 >> fn; } 'example.vcf
Dan Bennett
@DanBennett Merci beaucoup pour l'astuce! J'ai mis à jour ma réponse et j'ai également simplifié la logique de redirection / notes liées à la redirection fixe.
maxschlepzig
11
csplit -f vcard input.txt -z '/END:VCARD/+1' '{*}'
Ignacio Vazquez-Abrams
la source
5

La version GNU de csplit peut définir l'extension - la réponse d'Ignacio est, je pense, la plus concise, elle a juste besoin de cette dernière modification pour obtenir l'extension - en utilisant le format 'printf':

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

Voici l'extrait pertinent de la csplitpage de manuel gnu :

   -b, --suffix-format=FORMAT
          use sprintf FORMAT instead of %02d
Keithel
la source
J'utilisais mac et il m'a fallu un certain temps pour comprendre l'utilisation de gcsplit à la place, mais une fois que j'ai fait cette réponse m'a aidé.
Luke Gedeon
4

Vous pouvez utiliser ce script pour faire le travail. Cela s'appelle split-vcf-file .

Exemple d'utilisation

$ 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

Pour exécuter le script:

mkdir vcf_files
split_vcf.pl  -i current.vcf -o vcf_files
slm
la source
split_vcf.pl est une version Windows. pour unix, modifiez le sous make_filename qui ajoutait un "\" dans les noms de fichiers.
J Dan
4

En utilisant GNU Parallel, vous pouvez faire:

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

Ou si vous pouvez réfuter http://oletange.blogspot.com/2013/10/useless-use-of-cat.html, vous pouvez l'utiliser à la place:

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

Voir plus d'exemples: http://www.gnu.org/software/parallel/man.html

Regardez les vidéos d'introduction: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Installation en 10 secondes:

$ (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
la source