如何使用关键字边界拆分文件

den*_*zer 16 split files

我有一个包含大量 vcard 的 vcf 文件。

将 vcf 文件导入到 Outlook 时,它似乎只导入了第一个 vcard。

因此我想把它们分开。

鉴于 vcard 以

BEGIN:VCARD
Run Code Online (Sandbox Code Playgroud)

并以

END:VCARD
Run Code Online (Sandbox Code Playgroud)

将每个 vcard 拆分为自己的文件的最佳方法是什么。

谢谢

更新

感谢所有的回应。对于这种性质的问题,有多种方法可以给猫剥皮。这是我选择我所做的那个的原因。

围捕

这是我从每个答案中喜欢的内容以及促使我选择其中一个答案的汇总。

  • csplit: 我真的很喜欢这种方法的简洁性。我只是希望它也能够设置文件扩展名。
  • gawk: 它做到了我要求的一切。
  • paralell: 工作了。但我不得不安装新东西。(它还决定在我的主目录中创建一个新的 /bin 目录)
  • perl:我喜欢它根据联系人的姓名创建 vcf。但是 -o 选项并没有真正起作用

结论

  • 所以第一个走的是perl因为有点破
  • 接下来是paralell因为我必须安装新东西
  • 接下来是csplit,因为据我所知,它无法在输出文件上创建扩展名
  • 所以这个奖项授予了 gawk,因为它是一个随时可用的实用程序,而且功能足够多,我可以稍微修改和更改文件名。加分的cmp太:)

max*_*zig 11

您可以使用 awk 来完成这项工作:

$ 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
Run Code Online (Sandbox Code Playgroud)

细节

awk 行的工作方式如下:a是在每一BEGIN:VCARD行递增的计数器,同时使用 sprintf 构造输出文件名(存储在 中fn)。对于每一行,当前行 ( $0) 被附加到当前文件(名为fn)。

最后的echo $?意思cmp是成功了,即所有连接的单个文件都等于原始示例 vcf 示例。

请注意,awk 中的输出重定向与 shell 中的工作方式不同。这意味着使用> fnawk 首先检查文件是否已经打开。如果它已经打开,则 awk附加到它。如果不是,则它会打开并截断它。

由于这种重定向逻辑,我们必须显式关闭隐式打开的文件,否则在输入文件包含许多记录的情况下,调用将达到打开文件限制。


Ign*_*ams 11

csplit -f vcard input.txt -z '/END:VCARD/+1' '{*}'
Run Code Online (Sandbox Code Playgroud)


Ole*_*nge 5

使用 GNU Parallel 您可以执行以下操作:

cat foo.vcf | parallel --pipe -N1 --recstart BEGIN:VCARD 'cat >{#}'
Run Code Online (Sandbox Code Playgroud)

或者,如果您可以反驳http://oletange.blogspot.com/2013/10/useless-use-of-cat.html,您可以改用它:

< foo.vcf parallel --pipe -N1 --recstart BEGIN:VCARD 'cat >{#}'
Run Code Online (Sandbox Code Playgroud)

查看更多示例:http : //www.gnu.org/software/parallel/man.html

观看介绍视频:https : //www.youtube.com/playlist? list =PL284C9FF2488BC6D1

10秒安装:

$ (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 883c667e01eed62f975ad28b6d50e22a
12345678 883c667e 01eed62f 975ad28b 6d50e22a
$ md5sum install.sh | grep cc21b4c943fd03e93ae1ae49e28573c0
cc21b4c9 43fd03e9 3ae1ae49 e28573c0
$ sha512sum install.sh | grep da012ec113b49a54e705f86d51e784ebced224fdf
79945d9d 250b42a4 2067bb00 99da012e c113b49a 54e705f8 6d51e784 ebced224
fdff3f52 ca588d64 e75f6033 61bd543f d631f592 2f87ceb2 ab034149 6df84a35
$ bash install.sh
Run Code Online (Sandbox Code Playgroud)


Kei*_*hel 5

csplit 的 Gnu 版本可以设置扩展名 - 我认为 Ignacio 的答案是最简洁的,它只需要最后一点调整即可获得扩展名 - 使用“printf”格式:

csplit -f vcard -b %02d.vcard input.txt -z '/END:VCARD/+1' '{*}'
Run Code Online (Sandbox Code Playgroud)

这是来自 gnucsplit手册页的相关片段:

   -b, --suffix-format=FORMAT
          use sprintf FORMAT instead of %02d
Run Code Online (Sandbox Code Playgroud)