有时候必须把文件分割成多个更小的片段。很久以前,我们必须分割文件,才能将大量数据放入多张软盘中。不过如今我们分割文件就是出于其他目的了,比如为提高可读性、生成日志以及发送有大小限制的E-mail附件。在这则攻略中我们会看到如何将文件分割成不同的大小。

2.11.1 工作原理

split命令可以用来分割文件。该命令接受文件名作为参数,然后创建出一系列体积更小的文件,其中依据字母序排在首位的那个文件对应于原始文件的第一部分,排在次位的文件对应于原始文件的第二部分,以此类推。

例如,通过指定分割大小,可以将 100 KB 的文件分成一系列 10 KB 的小文件。在split命令中,
除了k(KB),我们还可以使用M(MB)、G(GB)、c(byte)和w(word)。

  1. $ split -b 10k data.file
  2. $ ls
  3. data.file xaa xab xac xad xae xaf xag xah xai xaj

上面的命令将data.file分割成了 10 个大小为 10 KB 的文件。这些新文件以 xab xac xad 的形式命名。split默认使用字母后缀。如果想使用数字后缀,需要使用-d选项。此外,-a length 可以指定后缀长度:

  1. $ split -b 10k data.file -d -a 4
  2. $ ls
  3. data.file x0009 x0019 x0029 x0039 x0049 x0059 x0069 x0079

2.11.2 补充内容

来看看split命令的其他选项。

为分割后的文件指定文件名前缀

之前那些分割后的文件名都是以x作为前缀。如果要分割的文件不止一个,我们自然希望能自己命名这些分割后的文件,这样才能够知道这些文件分别属于哪个原始文件。这可以通过提供一个前缀作为最后一个参数来实现。

这次我们使用split_file作为文件名前缀,重新执行上一条命令:

  1. $ split -b 10k data.file -d -a 4 split_file
  2. $ ls
  3. data.file split_file0002 split_file0005 split_file0008
  4. strtok.c
  5. split_file0000 split_file0003 split_file0006 split_file0009
  6. split_file0001 split_file0004 split_file0007

如果不想按照数据块大小,而是根据行数来分割文件的话,可以使用-l no_of_lines

  1. #分割成多个文件,每个文件包含10行
  2. $ split -l 10 data.file

csplit实用工具能够基于上下文来分隔文件。它依据的是行计数或正则表达式。这个工具对于日志文件分割尤为有用。

看一个日志文件示例:

  1. $ cat server.log
  2. SERVER-1
  3. [connection] 192.168.0.1 success
  4. [connection] 192.168.0.2 failed
  5. [disconnect] 192.168.0.3 pending
  6. [connection] 192.168.0.4 success
  7. SERVER-2
  8. [connection] 192.168.0.1 failed
  9. [connection] 192.168.0.2 failed
  10. [disconnect] 192.168.0.3 success
  11. [connection] 192.168.0.4 failed
  12. SERVER-3
  13. [connection] 192.168.0.1 pending
  14. [connection] 192.168.0.2 pending
  15. [disconnect] 192.168.0.3 pending
  16. [connection] 192.168.0.4 failed

我们需要将这个日志文件分割成server1.logserver2.logserver3.log,这些文件的内容分别取自原文件中不同的SERVER部分。实现方法如下:

  1. $ csplit server.log /SERVER/ -n 2 -s {*} -f server -b "%02d.log"
  2. $ rm server00.log
  3. $ ls
  4. server01.log server02.log server03.log server.log

下面是这个命令的详细说明:

  • /SERVER/用来匹配特定行,分割过程即从此处开始。
  • /[REGEX]/用于描述文本模式。它从当前行(第一行)一直复制到(但不包括)包含SERVER的匹配行。
  • {*}表示根据匹配重复执行分割操作,直到文件末尾为止。可以用{整数}的形式来指定分割执行的次数。
  • -s使命令进入静默模式,不打印其他信息。
  • -n指定分割后的文件名后缀的数字个数,例如010203等。
  • -f指定分割后的文件名前缀(在上面的例子中,server就是前缀)。
  • -b指定后缀格式。例如%02d.log,类似于C语言中printf的参数格式。在这里:**文件名=前缀 + 后缀**,也就是server + %02d.log

因为分割后得到的第一个文件没有任何内容(匹配的单词就位于文件的第一行中),所以我们删除server00.log