Shell 分割文件与数据,有时候必须把文件分割成多个更小的片段。很久以前,我们必须分割文件,才能将大量数据放入多张软盘中。不过如今我们分割文件就是出于其他目的了,比如为提高可读性、生成日志以及发送有大小限制的E-mail附件。在这则攻略中我们会看到如何将文件分割成不同的大小。
工作原理
split
命令可以用来分割文件。该命令接受文件名作为参数,然后创建出一系列体积更小的文件,其中依据字母序排在首位的那个文件对应于原始文件的第一部分,排在次位的文件对应于原始文件的第二部分,以此类推。
例如,通过指定分割大小,可以将100KB的文件分成一系列10KB的小文件。在split
命令中,除了k
(KB),我们还可以使用M
(MB)、G
(GB)、c
(byte)和w
(word)。
$ split -b 10k data.file
$ ls
data.file xaa xab xac xad xae xaf xag xah xai xaj
上面的命令将data.file分割成了10个大小为10KB的文件。这些新文件以xab
、xac
、xad
的形式命名。split
默认使用字母后缀。如果想使用数字后缀,需要使用-d
选项。此外, -a length
可以指定后缀长度:
$ split -b 10k data.file -d -a 4
$ ls
data.file x0009 x0019 x0029 x0039 x0049 x0059 x0069 x0079
补充内容
来看看split
命令的其他选项。
为分割后的文件指定文件名前缀
之前那些分割后的文件名都是以x
作为前缀。如果要分割的文件不止一个,我们自然希望能自己命名这些分割后的文件,这样才能够知道这些文件分别属于哪个原始文件。这可以通过提供一个前缀作为最后一个参数来实现。
这次我们使用split_file作为文件名前缀,重新执行上一条命令:
$ split -b 10k data.file -d -a 4 split_file
$ ls
data.file split_file0002 split_file0005 split_file0008
strtok.c
split_file0000 split_file0003 split_file0006 split_file0009
split_file0001 split_file0004 split_file0007
如果不想按照数据块大小,而是根据行数来分割文件的话,可以使用 -l no_of_lines
:
# 分割成多个文件,每个文件包含10行
$ split -l 10 data.file
csplit
实用工具能够基于上下文来分隔文件。它依据的是行计数或正则表达式。这个工具对于日志文件分割尤为有用。
看一个日志文件示例:
$ cat server.log
SERVER-1
[connection] 192.168.0.1 success
[connection] 192.168.0.2 failed
[disconnect] 192.168.0.3 pending
[connection] 192.168.0.4 success
SERVER-2
[connection] 192.168.0.1 failed
[connection] 192.168.0.2 failed
[disconnect] 192.168.0.3 success
[connection] 192.168.0.4 failed
SERVER-3
[connection] 192.168.0.1 pending
[connection] 192.168.0.2 pending
[disconnect] 192.168.0.3 pending
[connection] 192.168.0.4 failed
我们需要将这个日志文件分割成server1.log、server2.log和server3.log,这些文件的内容分别取自原文件中不同的SERVER
部分。实现方法如下:
$ csplit server.log /SERVER/ -n 2 -s {*} -f server -b "%02d.log"
$ rm server00.log
$ ls
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。