Linux笔记之如何分割文件或管道流:split
一、简介
在Linux中合并文件可以使用cat命令,后面跟上要合并的文件然后重定向到一个新的文件中即可,甚至可以追加合并。但如果要将一个大文件分割为多个小文件应该如何操作呢?
在Linux的coreutils中有一个工具split实现了这个功能,可以把一个大文件切割为多个小文件,甚至可以借助管道将流切成固定大小的文件,切割规则可以使用行数,也可以使用字节数。
二、预备测试数据
先生成一个稍微大点的文件,接下来就切割这个文件:
#! /bin/bash for((i=0;i<1000000;i++)); do echo $i >> data done
将上面这段保存为gen-data.sh,然后执行生成一个名为data有1000000行的文本文件。
三、按行数分割
将data按照每10000行为一个文件切割:
对于切割后的小文件的命名,名称由“前缀”+“后缀”的形式组成,所有的小文件拥有相同的前缀,前缀是为了将它们归为一类,默认的前缀为x,后缀是一个自增的序列,即给每个小文件编号,默认从aa开始递增编号。
自定义前缀和后缀,-d表示使用数字后缀:
上面的自增好像有点bug,因为默认的后缀长度为2而生成的文件数位数超出了2,所以后面的部分计数看起来就有点奇怪,可以指定后缀长度修正它:
现在编号没有问题了。
四、按字节分割
还可以对文件按照字节数进行分割,一般用于二进制文件,这里为了方便直接拿data文件做分割了:
五、从标准输入读入
一般说的从标准输入读取实际的应用场景一般都是从管道中读入,所以可以假设一个场景,有一个程序随机的输出一些信息到标准输出, 现在想每100000行存为一个文件方便后续操作,如何做比较方便呢?
一般情况下可能会使用一些脚本语言做这个每n行切换一个文件的操作,但这种屁大点事就要引入一个python或ruby之类的真是浪费,使用split一行就可以搞定。
将前面的gen-data.sh复制为gen-data-to-stdout.sh改为直接输出到标准输出:
#! /bin/bash while true do echo $i done
现在有了一个会不断输出信息的程序,接下来使用split实现每n行输出一个新文件的功能:
./gen-data-to-stdout.sh | split -l 100000 -d -a 10 - foo-stdout-
然后查看当前文件夹下的输出:
上面是一个对管道流按照行数分割的例子,接下来看一个对管道流按照字节数分割的例子,对tar打包后的文件按照2g为单位进行分割:
tar zcvf - foo-stdout-* | split -b 2G -d -a 3 - foo-stdout.tar.gz.
六、思考:为什么分割为的小文件需要前缀呢?
默认情况下分割后的小文件放在当前文件夹下,不会自动创建新的文件夹来存放它们(想一想创建文件夹的目的是什么呢),前缀的目的就是为了提供一种方式能够方便的找到分割后的小文件以对其进行批量操作,比如对data文件进行分割操作,分割为了data-part-000、data-part-001、data-part-002、data-part-003 ...等一千个小文件,那么可以使用前缀data-part-*对这一千个小文件进行批量操作,即使当前目录下还有完全无关的千八百个其它文件也对这个操作不影响,只要前缀不冲突就行。如果没有前缀的话分割后的这一千个小文件就跟其它的文件混在一起了,要批量操作它们很困难。
总结:对分割为的小文件加相同的前缀是为了方便找到它们,实际上可以将前缀看做是一个组名称,使用组前缀将这些小文件打成一组。
七、总结
使用split可以将一个大文件分割为多个小文件,分割方式可以使用字节或行数,也可以从管道中读入数据流对数据流按照行数或字节数分割。
.