2.10 分割文件和数据

在某些情况下,必须把文件分割成多个更小的片段。早期像软盘之类的设备容量都很有限,那么,将文件分割得更小些,以便能够存储到多张磁盘中就显得至关重要了。不过如今我们分割文件就是出于其他目的了,比如为提高可读性、生成日志等。

2.10.1 工作原理

生成一个大小为100KB的测试文件(data.file):

  1. $ dd if=/dev/zero bs=100k count=1 of=data.file

上面的命令会创建一个大小为100KB而文件内容全部是0的文件。

你可以指定分割大小,将文件分割成多个更小的文件:

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

上面的命令将data.file分割成多个文件,每一个文件大小为10KB。这些文件以xabxacxad这种方式命名。这意味着它们都有一个字母后缀。如果想以数字为后缀,可以另外使用-d参数。此外,使用 -a length就可以指定后缀长度:

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

除了k(KB),我们还可以使用M(MB)、G(GB)、c(byte)、w(word)等。

2.10.2 补充内容

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

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

上面那些分割后的文件都有一个文件名前缀“x”。我们也可以通过提供一个前缀名以使用我们自己的文件名前缀。split命令最后一个参数是PREFIX,其格式如下:

  1. $ split [COMMAND_ARGS] PREFIX

我们加上分隔文件的前缀名来运行先前那个命令:

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

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

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

另一个有趣的的工具是csplit。它能够依据指定的条件和字符串匹配选项对log文件进行分割。不妨看看这个工具是如何运作的。

csplitsplit工具的一个变体。split只能够根据数据大小或行数分割文件,而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.log、server2.log和server3.log,这些文件的内容分别取自原文件中不同的SERVER部分。那么,可以使用下面的方法来实现:

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

有关这个命令的详细说明如下所示。

  • /SERVER/ 用来匹配某一行,分割过程即从此处开始。

  • /[REGEX]/ 表示文本样式。包括从当前行(第一行)直到(但不包括)包含“SERVER”的匹配行。

  • {*} 表示根据匹配重复执行分割,直到文件末尾为止。可以用{整数}的形式来指定分割执行的次数。

  • -s 使命令进入静默模式,不打印其他信息。

  • -n 指定分割后的文件名后缀的数字个数,例如01、02、03等。

  • -f 指定分割后的文件名前缀(在上面的例子中,server就是前缀)。

  • -b 指定后缀格式。例如“%02d.log”,类似于C语言中printf的参数格式。在这里文件名=前缀+后缀=server + %02d.log

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