在Linux最常用的文件生成和切片工具是dd,它功能比较全面,但无法以行为单位提取文件数据,也无法直接将文件按大小或行数进行均分(除非借助循环)。另两款数据分割工具split和csplit能够比较轻松地实现这些需求。csplit是split的升级版。

在处理很大的文件时,一个非常高效的思路是将大文件切割成多个小文件片段,然后再通过多个进程/线程对各个小文件进行操作,最后合并总数居。就像sort命令,它在实现排序时,底层算法就涉及到了将一个大文件切割成多个临时小文件。

1.1 dd命令

从if指定的文件读取数据,写入到of指定的文件。使用bs指定读取和写入的块大小,使用count指定读取和写入的数据块数量,bs和count相乘就是文件总大小。可以指定skip忽略读取if指定文件的前多少个块,seek指定写入到of指定文件时忽略前多少个块。

dd if=/dev/zero of=/tmp/abc. bs=1M count=

if是input file,of是output file;bs有c(1byte)、w(2bytes)、b(512bytes)、kB(1000bytes)、K(1024bytes)、MB(1000)、M(1024)和GB、G等几种单位。因此,不要随意在单位后加上字母B。

假设现有文件CentOS.iso的大小1.3G,需要将其切分后还原,切分的第一个小文件大小为500M。

dd if=/tmp/CentOS.iso of=/tmp/CentOS1.iso bs=2M count=

生成第二个小文件,由于第二个小文件不知道具体大小,所以不指定count选项。由于第二个小文件要从第500M处开始切分,于是需要忽略CentOS.iso的前500M。假设bs=2M,于是skip掉的数据块数量为250。

dd if=/tmp/CentOS.iso of=/tmp/CentOS2.iso bs=2M skip=

现在CentOS.iso=CentOS1.iso+CentOS2.iso。可以将CentOS[1-2].iso还原。

cat CentOS1.iso CentOS2.iso >CentOS_m.iso

比较CentOS_m.iso和CentOS.iso的md5值,它们是完全一样的。

shell> md5sum CentOS_m.iso CentOS.iso
504dbef14aed9b5990461f85d9fdc667 CentOS_m.iso
504dbef14aed9b5990461f85d9fdc667 CentOS.iso

那么seek选项呢?和skip有什么区别?skip选项是忽略读取时的前N个数据块,而seek是忽略写入文件的前N个数据块。假如要写入的文件为a.log,则seek=2时,将从a.log的第3个数据块开始追加数据,如果a.log文件本身大小就不足2个数据块,则缺少的部分自动使用/dev/zero填充。

于是,在有了CentOS1.iso的基础上,要将其还原为和CentOS.iso相同的文件,可以使用下面的方法:

dd if=/tmp/CentOS.iso of=/tmp/CentOS1.iso bs=2M skip= seek=

还原后,它们的md5值也是相同的。

shell> md5sum CentOS1.iso CentOS.iso
504dbef14aed9b5990461f85d9fdc667 CentOS1.iso
504dbef14aed9b5990461f85d9fdc667 CentOS.iso

1.2 split命令

split工具的功能是将文件切分为多个小文件。既然要生成多个小文件,必然要指定切分文件的单位,支持按行切分以及按文件大小切分,另外还需解决小文件命名的问题。例如,文件名前缀、后缀。如果未明确指定前缀,则默认的前缀为"x"。

以下是命令的语法说明:

split [OPTION]... [INPUT [PREFIX]]

-a N:生成长度为N的后缀,默认N=
-b N:每个小文件的N,即按文件大小切分文件。支持K,M,G,T(换算单位1024)或KB,MB,GB(换算单位1000)等,默认单位为字节
-l N:每个小文件中有N行,即按行切分文件
-d N:指定生成数值格式的后缀替代默认的字母后缀,数值从N开始,默认为0。例如两位长度的后缀01//
--additional-suffix=string:为每个小文件追加额外的后缀,例如加上".log"。有些老版本不支持该选项,在CentOS .2上已支持。
-n CHUNKS:将文件按照指定的CHUNKS方式进行分割。CHUNKS的有效形式有(具体用法见后文):N、l/N、l/K/N、K/N、r/N、r/K/N
--filter CMD:不再直接切割输出到文件,而是切割后作为管道的输入,通过管道将切割的数据传递给CMD执行。如果需要指定文件,则split自动使用$FILE变量。见后文示例 INPUT:指定待切分的输入文件,如要切分标准输入,则使用"-"
PREFIX:指定小文件的前缀,如果未指定,则默认为"x"

1.2.1 基本用法

例如,将/etc/fstab按行切分,每5行切分一次,并指定小文件的前缀为"fs_",后缀为数值后缀,且后缀长度为2。

[root@xuexi ~]# split -l  -d -a  /etc/fstab fs_

[root@xuexi ~]# ls
fs_00 fs_01 fs_02

查看任一小文件。

[root@xuexi ~]# cat fs_01
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(), findfs(), mount() and/or blkid() for more info
#
UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 / xfs defaults
UUID=367d6a77-033b--bbcb-416705ead095 /boot xfs defaults

可以将这些切分后的小文件重新组装还原。例如,将上面的三个小文件还原为~/fstab.bak。

[root@xuexi ~]# cat fs_0[-] >~/fstab.bak

还原后,它们的内容是完全一致的。可以使用md5sum比较。

[root@xuexi ~]# md5sum /etc/fstab ~/fstab.bak
29b94c500f484040a675cb4ef81c87bf /etc/fstab
29b94c500f484040a675cb4ef81c87bf /root/fstab.bak

还可以将标准输入的数据进行切分,并分别写入到小文件中。例如:

[root@xuexi ~]# seq    | split -l  -d - new_

[root@xuexi ~]# ls new*
new_00 new_01 new_02

可以为每个小文件追加额外的后缀。有些老版本的split不支持该选项,而是在csplit上支持的,但是新版本的split已经支持。例如,加上".log"。

[root@xuexi ~]# seq    | split -l  -d -a  --additional-suffix=".log" - new1_

[root@xuexi ~]# ls new1*
new1_000.log new1_001.log new1_002.log new1_003.log

1.2.2 按CHUNKS进行分割

split的"-n"选项是按照CHUNK的方式进行文件切割:

'-e' 当使用-n时,不要生成空文件。例如5行数据,却要求按行切割成100个文件,显然第5个文件之后都是空文件

'-u --unbuffered' 当使用-n的r模式时,不要缓冲input,每读一行就立即拷贝给输出,所以该选项可能会比较慢

'-n CHUNKS'
'--number=CHUNKS'
Split INPUT to CHUNKS output files where CHUNKS may be:
N 根据文件大小均分为N个文件(最后一个文件可能大小不均)
K/N 输出(打印到屏幕、标准输出)N个文件中的第K个文件内容(不是切割后再找到这个文件进行输出,而是切割到这个文件时立即输出)
l/N 按行的方式均分为N个文件(最后一个文件可能行数不均)
l/K/N 按l/N切割的同时,输出属于第K个文件的内容
r/N 类似于l的形式,但对行进行轮询方式切割。例如第一行到第一个文件,第二行到第二个文件
r/K/N 按照r/N切割时,输出第K个文件的内容 其中大写字母K和N是我们按需指定的数值,l或r是代表模式的字母

可能不是很好理解,给几个示例就很清晰了。

假如文件1.txt中有a-z,每个字母占一行,共26行。将这个文件进行切割:

1.指定CHUNK=N或K/N时

将1.txt均分为5个文件。由于1.txt共52字节(每行中,字母一个字节,换行符一个字节),所以分割后每个文件10字节,最后一个文件12字节。

[root@redisa-b a]# split -n  .txt fs_

[root@redisa-b a]# ls -l
total
-rw-r--r-- root root Oct : .txt
-rw-r--r-- root root Oct : fs_aa
-rw-r--r-- root root Oct : fs_ab
-rw-r--r-- root root Oct : fs_ac
-rw-r--r-- root root Oct : fs_ad
-rw-r--r-- root root Oct : fs_ae

如果再指定K/N的K,例如指定为2,则输出属于fs_ab文件中的内容:

[root@redisa-b a]# split -n / .txt fs_
f
g
h
i
j

2.指定CHUNK=l/N或l/K/N时

这时将按照行的总数量进行均分。例如,将1.txt中的26行分割成5个文件,前4个文件将各有5行,第5个文件将有6行:

[root@redisa-b a]# split -n l/ .txt fs_

[root@redisa-b a]# wc -l fs_*
fs_aa
fs_ab
fs_ac
fs_ad
fs_ae
total

如果指定K,则输出属于第K个文件的内容:

[root@redisa-b a]# split -n l// .txt fs_
f
g
h
i
j

3.指定CHUNK=r/N或r/K/N时

使用r时,将每切割一行就轮询到下一个文件,轮完所有文件再返回来切割到第一个文件。

直接看结果:

[root@redisa-b a]# split -n r/ .txt fs_  

[root@redisa-b a]# head -n  fs*
==> fs_aa <==
a
f ==> fs_ab <==
b
g ==> fs_ac <==
c
h ==> fs_ad <==
d
i ==> fs_ae <==
e
j

a输出到第1个文件,b输出到第2个文件,c输出到第3个文件,依此类推。

指定K时,将输出第K个文件的内容:

[root@redisa-b a]# split -n r// .txt fs_
b
g
l
q
v

1.2.3 filter CMD将切割结果传递给指定命令

默认情况下split是将文件切割传递到各文件片段中,如果使用--filter选项,则不再切割到文件片段中,而是通过管道的形式传递给CMD进行处理。CMD处理时,有可能并不需要将数据存储到文件中,但如果需要将处理后的数据再分片段保存到多个文件中,则可以使用$FILE来表示(这是split识别的变量,要避免被shell解析),就像split的普通切割模式一样。

例如,读取1.txt中的26行,每5行管道传递一次,然后使用echo将它们输出:

[root@redisa-b a]# split -n l/ --filter='xargs -i echo ---:{}' .txt
---:a
---:b
---:c
---:d
---:e # 第1次通过管道传递的内容
---:f
---:g
---:h
---:i
---:j # 第2次通过管道传递的内容
---:k
---:l
---:m
---:n
---:o
---:p
---:q
---:r
---:s
---:t
---:u
---:v
---:w
---:x
---:y
---:z

这时split是没有生成任何小文件片段的。如果想要将上面的输出保存到小文件片段中,使用$FILE,这个变量是split内置变量,不能被shell解析,所以出现$split的地方必须使用单引号保护起来:

[root@redisa-b a]# split -n l/ --filter='xargs -i echo ---:{} >$FILE.log' .txt fs_

[root@redisa-b a]# ls
.txt fs_aa.log fs_ab.log fs_ac.log fs_ad.log fs_ae.log
[root@redisa-b a]# cat fs_aa.log
---:a
---:b
---:c
---:d
---:e

其中的$FILE就是split进行命名的部分。上面的小文件中,都是以fs_为前缀,以".log"为后缀。

filter有时候是很有用的,例如将一个大的压缩文件,切割成多个小的压缩文件。

xz -dc BIG.xz | split -b200G --filter='xz > $FILE.xz' - big-

"xz -dc"表示解压到标准输出,解压的数据流将传递给split,然后每200G就通过filter中的xz命令进行压缩,压缩后的文件名格式类似于"big-aa.xz big-ab.xz"。

1.3 csplit命令

split只能按行或按照大小进行切分,无法按段落切分。csplit是split的变体,功能更多,它主要是按指定上下文按段落分割文件。

csplit [OPTION]... FILE PATTERN...

描述:按照PATTERN将文件切分为"xx00","xx01", ...,并在标准输出中输出每个小文件的字节数。

选项说明:
-b FORMAT:指定文件后缀格式,格式为printf的格式,默认为%02d。表示后缀以2位数值,且不足处以0填充。
-f PREFIX:指定前缀,不指定是默认为"xx"。
-k:用于突发情况。表示即使发生了错误,也不删除已经分割完成的小文件。
-m:明确禁止文件的行去匹配PATTERN。
-s:(silent)不打印小文件的文件大小。
-z:如果切分后的小文件中有空文件,则删除它们。 FILE:待切分的文件,如果要切分标准输入数据,则使用"-"。 PATTERNs: INTEGER :数值,假如为N,表示拷贝1到N-1行的内容到一个小文件中,其余内容到另一个小文件中。
/REGEXP/[OFFSET]:从匹配到的行开始按照偏移量拷贝指定行数的内容到小文件中。
:其中OFFSET的格式为"+N"或"-N",表示向后和向前拷贝N行
%REGEXP%[OFFSET]:匹配到的行被忽略。
{INTEGER} :假如值为N,表示重复N此前一个模式匹配。
{*} :表示一直匹配到文件结尾才停止匹配。

假设文件内容如下:

[root@xuexi ~]# cat test.txt
SERVER-
[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-
[connection] 192.168.0.1 failed
[connection] 192.168.0.2 failed
[disconnect] 192.168.0.3 success
[CONNECTION] 192.168.0.4 pending
SERVER-
[connection] 192.168.0.1 pending
[connection] 192.168.0.2 pending
[disconnect] 192.168.0.3 pending
[connection] 192.168.0.4 failed

假设每个SERVER-n表示一个段落,于是要按照段落切分该文件,使用以下语句:

[root@xuexi ~]# csplit -f test_  -b %04d.log test.txt /SERVER/ {*}

"-f test_" 指定小文件前缀为"test_", "-b %04d.log" 指定文件后缀格式"00xx.log",它自动为每个小文件追加额外的后缀".log", "/SERVER/" 表示匹配的模式,每匹配到一次,就生成一个小文件,且匹配到的行是该小文件中的内容, "{*}" 表示无限匹配前一个模式即/SERVER/直到文件结尾,假如不知道{*}或指定为{1},将匹配一次成功后就不再匹配。

[root@xuexi ~]# ls test_*
test_0000.log test_0001.log test_0002.log test_0003.log

上面的文件中虽然只有三个段落:SERVER-1,SERVER-2,SERVER-3,但切分的结果生成了4个小文件,并且注意到第一个小文件大小为0字节。为什么会如此?因为在模式匹配的时候,每匹配到一行,这一行就作为下一个小文件的起始行。由于此文件第一行"SERVER-1"就被/SERVER/匹配到了,因此这一行是作为下一个小文件的内容,在此小文件之前还自动生成一个空文件。

生成的空文件可以使用"-z"选项来删除。

[root@xuexi ~]# csplit -f test1_ -z -b %04d.log test.txt /SERVER/ {*}

还可以指定只拷贝匹配到的行偏移数量。例如,匹配到行时,只拷贝它后面的1行(包括它自身共两行),但多余的行将放入下一个小文件中。

[root@xuexi ~]# csplit -f test2_ -z -b %04d.log test.txt /SERVER/+ {*}

第一个小文件只有两行。

[root@xuexi ~]# cat test2_0000.log
SERVER-
[connection] 192.168.0.1 success

SERVER-1段落的其余内容放入到了第二个小文件中。

[root@xuexi ~]# cat test2_0001.log
[connection] 192.168.0.2 failed
[disconnect] 192.168.0.3 pending
[connection] 192.168.0.4 success
SERVER-
[connection] 192.168.0.1 failed

同理第三个小文件也一样,直到最后一个小文件中存放剩余所有无法匹配的内容。

[root@xuexi ~]# cat test2_0003.log
[connection] 192.168.0.2 pending
[disconnect] 192.168.0.3 pending
[connection] 192.168.0.4 failed

指定"-s"或"-q"选项以静默模式运行,将不会输出小文件的大小信息。

[root@xuexi ~]# csplit -q -f test3_ -z -b %04d.log test.txt /SERVER/+ {*}

dd、split、csplit命令的更多相关文章

  1. Linux csplit命令详解

    Linux csplit命令 Linux csplit命令用于分割文件.拆解文件主要是split和csplit命令,如果说split是按大小来拆分的话,那么csplit则可按匹配来拆分: 将文件依照指 ...

  2. 【转】linux中的cut/tr/join/split/xargs命令

    1. cut命令 cut命令用于从文件或者标准输入中读取内容并截取每一行的特定部分并送到标准输出. 截取的方式有三种:一是按照字符位置,二是按照字节位置,三是使用一个分隔符将一行分割成多个field, ...

  3. Linux下dd和od命令备份查看硬盘mbr,并用vim修改!

    主引导记录(Master Boot Record,MBR),位于一个硬盘的0柱面.0盘面.1扇区,共512字节.具体划分依次为:引导代码区440字节.磁盘签名4字节.空白(Ox0000)2字节.MBR ...

  4. split命令_Linux split命令:切割(拆分)文件

    <Linux就该这么学>是一本基于最新Linux系统编写的入门必读书籍,内容面向零基础读者,由浅入深渐进式教学,销量保持国内第一,年销售量预期超过10万本.点此免费在线阅读. 15 分钟之 ...

  5. linux命令dd

    原文链接: http://blog.csdn.net/adaptiver/article/details/6672592 dd 使用dd这个linux命令可以创建一定大小文件. linux创建文件命令 ...

  6. [转帖]linux命令dd

    linux命令dd   dd 是diskdump 的含义 之前学习过 总是记不住 用的还是少. http://embeddedlinux.org.cn/emb-linux/entry-level/20 ...

  7. 磁盘,fdisk分区,MBR,dd命令

    光盘和磁盘.u盘.软盘.硬盘有什么区别 ①光盘: cdrom/dvdrom:光驱(光盘驱动器)    rom:只读    ram:可以擦写    cd:700M    dvd:4G ②软盘:flopp ...

  8. linux shell 学习笔记--内部命令学习

    .基本命令 新手必须要掌握的初级命令 ls 基本的列出所有文件的命令.但是往往就是因为这个命令太简单,所以我们总是低估它.比如 ,用 -R 选项,这是递归选项,ls 将会以目录树的形式列出所有文件, ...

  9. [置顶] Linux 常用命令集锦

    出处:http://www.vaikan.com/what-are-the-most-useful-swiss-army-knife-one-liners-on-unix/ Linux命令行里的&qu ...

随机推荐

  1. aji unorder_map

  2. 第十二章 FTP服务器安装与配置

    习题 1.简述FTP的连接模式. FTP的连接模式有PORT和PASV两种,其中PORT模式是主动模式,PASV是被动模式, 这里所说的主动和被动都是相对于服务器而言的.如果是主动模式,数据端口为20 ...

  3. 安装easygui

    1.下载0.96的easygui 官网: http://easygui.sourceforge.net/ 2.解压后得到文件夹,里面有两个文件分别为,setup.py和easygui.py 3.在py ...

  4. wxPyhon 的控件(摘抄)

    一.静态文本控件 wx.StaticText(parent, id, label, pos=wx.DefaultPosition,    size=wx.DefaultSize, style=0, n ...

  5. javascript中数组总结

    数组是所有高级语言都会有的东西,数组是JS中使用最多的类型之一,所以掌握JS中数组的用法相当有帮助: 由于JS是一门弱类型的语言,所以数组里面可以放各种不同的数据类型,比如 var a = [1993 ...

  6. 《HTTP权威指南》4-连接管理

    TCP连接 TCP/IP是全球计算机及网络设备都在使用的一种常见的分组交换网络分层协议集客户端应用程序可以打开一条TCP/IP连接.连接到可能运行在世界任何地方的服务器应用程序 TCP的可靠数据管道 ...

  7. 微信机器人 index

    <?phprequire_once ('src/wechat.php');$wechat = new wechat();$act = isset($_GET['act'])?$_GET['act ...

  8. [转]Understand QoS at OpenSwitch

    danny http://dannykim.me/danny/57771 2014.02.11 14:34:58 (*.193.128.184) 592 >>> Purpose Th ...

  9. Windows 10 IoT Serials 11 – 如何设置微软认知服务中EndPoint

    1.问题描述 在UWP应用开发过程中,如果要使用微软认知服务,很多开发者会使用Microsoft.Oxford.Face.Microsoft.Oxford.Vision的NuGet包来完成.如果在vi ...

  10. es5

    var arr1=["上海","北京","广州"]; var arr2=[12,22, 33,58,32,45,92]; // 数组.方法( ...