• dd、split、csplit命令


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

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

    dd命令                    

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

    [root@master nginx]# dd if=/dev/zero of=/tmp/abc.1 bs=1M count=20
    [root@master nginx]# ls /tmp/abc.1 -lh
    -rw-r--r-- 1 root root 20M 11月 29 16:45 /tmp/abc.1

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

    现有文件access.log.bak的大小271M,需要将其切分后还原,切分的第一个小文件大小为20M。

    [root@master ~]# dd if=/root/access.log.bak of=/root/access.txt bs=1M count=20
    记录了20+0 的读入
    记录了20+0 的写出
    20971520字节(21 MB)已复制,0.651758 秒,32.2 MB/秒
    [root@master ~]# ls -lh access.txt
    -rw-r--r-- 1 root root 20M 11月 29 16:49 access.txt

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

    [root@master ~]# dd if=/root/access.log.bak of=/root/access1.txt bs=1M skip=20
    记录了250+1 的读入
    记录了250+1 的写出
    263095966字节(263 MB)已复制,10.0785 秒,26.1 MB/秒
    [root@master ~]# ls access1.txt -lh
    -rw-r--r-- 1 root root 251M 11月 29 16:54 access1.txt

    split命令                          

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

    以下是命令的语法说明:

    split [OPTION]... [INPUT [PREFIX]]
    
    -a N:生成长度为N的后缀,默认N=2
    -b N:每个小文件的N,即按文件大小切分文件。支持K,M,G,T(换算单位1024)或KB,MB,GB(换算单位1000)等,默认单位为字节
    -l N:每个小文件中有N行,即按行切分文件
    -d N:指定生成数值格式的后缀替代默认的字母后缀,数值从N开始,默认为0。例如两位长度的后缀01/02/03
    --additional-suffix=string:为每个小文件追加额外的后缀,例如加上".log"。有些老版本不支持该选项,在CentOS 7.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"

     基本用法                                

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

    [root@master nginx]# split -l 5 -d -a 2 /etc/fstab fs_
    [root@master nginx]# ls fs* -lh
    -rw-r--r-- 1 root root  68 11月 29 17:01 fs_00
    -rw-r--r-- 1 root root 321 11月 29 17:01 fs_01
    -rw-r--r-- 1 root root  76 11月 29 17:01 fs_02

    [root@master nginx]# wc -l fs_00
    5 fs_00

    [root@master nginx]# cat fs_0[0-2] > fstab.bak
    [root@master nginx]# cat fstab.bak 
    
    #
    # /etc/fstab
    # Created by anaconda on Thu Aug 15 22:24:09 2019
    #
    # Accessible filesystems, by reference, are maintained under '/dev/disk'
    # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
    #
    /dev/mapper/centos-root /                       xfs     defaults        0 0
    UUID=dad1d5b9-e717-4e2f-b8f5-1ed587cabf91 /boot                   xfs     defaults        0 0
    /dev/mapper/centos-swap swap                    swap    defaults        0 0
    [root@master nginx]# md5sum fstab.bak /etc/fstab 
    f814419cfabc31ec2c045abfd74bf36a  fstab.bak
    f814419cfabc31ec2c045abfd74bf36a  /etc/fstab

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

    [root@master nginx]# seq 1 2 15 | split -l 3 -d - new_
    [root@master nginx]# ls -l new_*
    -rw-r--r-- 1 root root 6 11月 29 17:08 new_00
    -rw-r--r-- 1 root root 7 11月 29 17:08 new_01
    -rw-r--r-- 1 root root 6 11月 29 17:08 new_02

    按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@master nginx]# dd if=/dev/zero of=1.txt bs=1K count=52
    记录了52+0 的读入
    记录了52+0 的写出
    53248字节(53 kB)已复制,0.00223804 秒,23.8 MB/秒
    [root@master nginx]# ls -l 1.txt -h
    -rw-r--r-- 1 root root 52K 11月 29 17:12 1.txt
    [root@master nginx]# split -n 5 1.txt fs_
    [root@master nginx]# ls fs_* -lh
    -rw-r--r-- 1 root root 11K 11月 29 17:14 fs_aa
    -rw-r--r-- 1 root root 11K 11月 29 17:14 fs_ab
    -rw-r--r-- 1 root root 11K 11月 29 17:14 fs_ac
    -rw-r--r-- 1 root root 11K 11月 29 17:14 fs_ad
    -rw-r--r-- 1 root root 11K 11月 29 17:14 fs_ae

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

    [root@master nginx]# split -n l/5 1.txt fs
    [root@master nginx]# ls -l fs*
    -rw-r--r-- 1 root root 53248 11月 29 17:16 fs_aa
    -rw-r--r-- 1 root root     0 11月 29 17:16 fs_ab
    -rw-r--r-- 1 root root     0 11月 29 17:16 fs_ac
    -rw-r--r-- 1 root root     0 11月 29 17:16 fs_ad
    -rw-r--r-- 1 root root     0 11月 29 17:16 fs_ae

    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@master nginx]# cat test.txt 
    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 pending
    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

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

    [root@master nginx]# csplit -f test_ -b %04d.log test.txt /SERVER/ {*}
    0
    140
    139
    140
    [root@master nginx]# ls
    1.txt access.log test_0000.log test_0001.log test_0002.log test_0003.log test.txt

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

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

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

    [root@master nginx]# csplit -f test1_ -z -b %04d.log test.txt /SERVER/ {*}
    140
    139
    140
    [root@master nginx]# ls test[0-9]* -l
    -rw-r--r-- 1 root root 140 11月 29 17:25 test1_0000.log
    -rw-r--r-- 1 root root 139 11月 29 17:25 test1_0001.log
    -rw-r--r-- 1 root root 140 11月 29 17:25 test1_0002.log

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

    [root@master nginx]# csplit -f test2_ -z -b %04d.log test.txt /SERVER/+2 {*}
    42
    139
    140
    98
    [root@master nginx]# ls test[0-9]* -l
    -rw-r--r-- 1 root root  42 11月 29 17:27 test2_0000.log
    -rw-r--r-- 1 root root 139 11月 29 17:27 test2_0001.log
    -rw-r--r-- 1 root root 140 11月 29 17:27 test2_0002.log
    -rw-r--r-- 1 root root  98 11月 29 17:27 test2_0003.log

    第一个小文件只有两行。

    [root@master nginx]# cat test2_0000.log 
    SERVER-1
    [connection] 192.168.0.1 success

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

    [root@master nginx]# cat test2_0001.log
    [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

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

    [root@master nginx]# 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@master nginx]# csplit -q -f test3_ -z -b %04d.log test.txt /SERVER/+2 {*}
    [root@master nginx]# ls
    1.txt  access.log  test3_0000.log  test3_0001.log  test3_0002.log  test3_0003.log  test.txt
  • 相关阅读:
    ajax传json
    JSON 转 VO
    字符串转数组
    "No 'Access-Control-Allow-Origin' header"跨域问题CROS
    jdbc连接SQLServer
    Jquery判断checkbox选中状态
    JSON与null
    点击劫持
    Eclipse 入手配置
    SQL练习(一)
  • 原文地址:https://www.cnblogs.com/liujunjun/p/11958956.html
Copyright © 2020-2023  润新知