美文网首页
19. 文本处理

19. 文本处理

作者: 独木舟的木 | 来源:发表于2019-02-05 20:04 被阅读5次

    [TOC]

    文本应用程序

    cat 连接文件并且打印到标准输出

    • -A 选项,在文本中显示非打印字符。
    $ cat -A foo.txt 
       The quick brown fox jumped over the lazy dog.$
    
    • -n 选项,给文本行添加行号。
    • -s 选项,禁止输出多个空白行。
    cat > foo.txt
    The quick brown fox
    
    jump over the lazy dog.
    ^C
    $ cat -ns foo.txt 
         1  The quick brown fox
         2
         3  jump over the lazy dog.
    

    sort 给文本行排序

    sort 程序对标准输入的内容,或命令行中指定的一个或多个文件进行排序,然后把排序结果发送到标准输出。

    $ sort > foo.txt
    c
    b
    a
    # Ctrl+D 表示文件的结尾。
    
    $ cat foo.txt 
    a
    b
    c
    
    常见的 sort 选项 长选项 描述
    -b --ignore-leading-blanks 默认情况下,对整行进行排序,从每行的第一个字符开始。这个选项导致 sort 程序忽略 每行开头的空格,从第一个非空白字符开始排序。
    -f --ignore-case 让排序不区分大小写。
    -n --numeric-sort 基于字符串的长度来排序。使用此选项允许根据数字值执行排序,而不是字母值。
    -r --reverse 按相反顺序排序。结果按照降序排列,而不是升序。
    -k --key=field1[,field2] 对从 field1 到 field2 之间的字符排序,而不是整个文本行。看下面的讨论。
    -m --merge 把每个参数看作是一个预先排好序的文件。把多个文件合并成一个排好序的文件,而没有执行额外的排序。
    -o --output=file 把排好序的输出结果发送到文件,而不是标准输出。
    -t --field-separator=char 定义域分隔字符。默认情况下,域由空格或制表符分隔。

    示例一:

    # 显示前10个文件,默认按路径名排序
    $ du -s /root/* | head
    75716   /root/Agora_Recording
    31420   /root/Agora_Recording_SDK_for_Linux_v2_2_2_FULL.tar.gz
    4       /root/foo.txt
    65728   /root/nodejs-v8.10.0
    64136   /root/p2p
    36456   /root/paxos
    13692   /root/PaxosUdp_let
    114528  /root/t-blockchain_screen
    28      /root/testDocument
    
    #  -nr 选项,反向数值排序,最大数值排列在第一位。
    # 这种排序起作用是因为数值出现在每行的开头。
    $ du -s /root/* | sort -nr | head
    114528  /root/t-blockchain_screen
    75716   /root/Agora_Recording
    65728   /root/nodejs-v8.10.0
    64136   /root/p2p
    36456   /root/paxos
    31420   /root/Agora_Recording_SDK_for_Linux_v2_2_2_FULL.tar.gz
    13692   /root/PaxosUdp_let
    28      /root/testDocument
    4       /root/foo.txt
    

    示例二(基于某个字段排序):

    $ ls -l /usr/bin | head
    total 431444
    -rwxr-xr-x 1 root   root       51920 Mar  3  2017 [
    -rwxr-xr-x 1 root   root          96 Nov 13 00:18 2to3-3.5
    -rwxr-xr-x 1 root   root       22696 Sep 28 06:10 aa-enabled
    -rwxr-xr-x 1 root   root       15072 Apr  9  2016 acpi_listen
    -rwxr-xr-x 1 root   root        6356 Dec 19 01:08 add-apt-repository
    -rwxr-xr-x 1 root   root       18888 May 16  2018 addpart
    lrwxrwxrwx 1 root   root          26 Aug 30 21:39 addr2line -> x86_64-linux-gnu-addr2line
    -rwxr-xr-x 1 root   root        2555 May 24  2018 apport-bug
    -rwxr-xr-x 1 root   root       13347 May 24  2018 apport-cli
    
    # -nr 选项,执行相反的数值排序
    # -k 5,让 sort 程序使用第五字段作为排序的关键值。
    # 空白字符(空格和制表符)被当作是字段间的界定符。
    $ ls -l /usr/bin | sort -nr -k 5 | head
    -rwxr-xr-x 1 root   root    22889264 Oct 23 20:11 mysql_embedded
    -rwxr-xr-x 1 root   root    18929936 Jul 19  2018 snap
    -rwxr-xr-x 1 root   root    14664464 Aug 11  2015 mongod
    -rwxr-xr-x 1 root   root    14537488 Aug 11  2015 mongorestore
    -rwxr-xr-x 1 root   root    14537488 Aug 11  2015 mongofiles
    -rwxr-xr-x 1 root   root    14508816 Aug 11  2015 mongodump
    -rwxr-xr-x 1 root   root    14504720 Aug 11  2015 mongostat
    -rwxr-xr-x 1 root   root    14504720 Aug 11  2015 mongoimport
    -rwxr-xr-x 1 root   root    14500624 Aug 11  2015 mongoexport
    -rwxr-xr-x 1 root   root    14496528 Aug 11  2015 mongooplog
    
    # 多键值排序语法
    # 1,1,“始于并且结束于第一个字段。”
    # 2n,第二个字段是排序的键值,并且按照数值排序。
    # b(忽略开头的空格),n(数值排序),r(逆向排序)
    $ sort --key=1,1 --key=2n distros.txt
    
    #  -k 3.7,指示 sort 程序使用一个排序键值,其始于第三个字段中的第七个字符,对应于年的开头。
    # 指定 -k 3.1 和 -k 3.4 来分离日期中的月和日。
    # b 选项用来删除日期字段中开头的空格
    sort -k 3.7nbr -k 3.1nbr -k 3.4nbr distros.txt
    Fedora         10    11/25/2008
    Ubuntu         8.10  10/30/2008
    SUSE           11.0  06/19/2008
    

    uniq 报告或者省略重复行

    当给定一个排好序的文件(包括标准输出),uniq 会删除任意重复行,并且把结果发送到标准输出。它常常和 sort 程序一块使用,来清理重复的输出。

    uniq 程序是一个传统的 Unix 工具,经常与 sort 程序一块使用, 但是这个 GNU 版本的 sort 程序支持一个 -u 选项,其可以从排好序的输出结果中删除重复行。

    uniq 程序能完成任务,其输入必须是排好序的数据,因为 uniq 只会删除相邻的重复行。

    # 新建一个包含重复的测试文件
    $ cat > foo.txt
    a
    b
    c
    a
    b
    c
    ^C
     
    # 数据没有排序好,输出不变:
    $ uniq foo.txt
    a
    b
    c
    a
    b
    c
    
    # 数据经过 sort 排序,uniq 才会删除重复项:
    $ sort foo.txt | uniq
    a
    b
    c
    
    $ sort foo.txt | uniq -c
          2 a
          2 b
          2 c
    
    常用的 uniq 选项 说明
    -c 输出所有的重复行,并且每行开头显示重复的次数。
    -d 只输出重复行,而不是特有的文本行。
    -f n 忽略每行开头的 n 个字段,字段之间由空格分隔,正如 sort 程序中的空格分隔符;然而,不同于 sort 程序,uniq 没有选项来设置备用的字段分隔符。
    -i 在比较文本行的时候忽略大小写。
    -s n 跳过(忽略)每行开头的 n 个字符。
    -u 只是输出独有的文本行。这是默认的。

    cut 从每行中删除文本区域

    cut 程序被用来从文本行中抽取文本,并把其输出到标准输出。
    cut 命令最好用来从其它程序产生的文件中抽取文本,而不是从人们直接输入的文本中抽取。

    选项 说明
    -c char_list 从文本行中抽取由 char_list 定义的文本。这个列表可能由一个或多个逗号 分隔开的数值区间组成。
    -f field_list 从文本行中抽取一个或多个由 field_list 定义的字段。这个列表可能 包括一个或多个字段,或由逗号分隔开的字段区间。
    -d delim_char 当指定 - f 选项之后,使用 delim_char 做为字段分隔符。默认情况下, 字段之间必须由单个 tab 字符分隔开。
    --complement 抽取整个文本行,除了那些由 - c 和/或 - f 选项指定的文本。
    # -f 3,抽取第三段
    # -c 7-10,抽取从位置 7 到 10 的字符
    $ cut -f 3 distros.txt | cut -c 7-10
    
    # -d 选项,指定冒号做为字段分隔符。
    $ cut -d ':' -f 1 /etc/passwd | head
    root
    daemon
    bin
    sys
    sync
    games
    man
    lp
    mail
    news
    

    paste 合并文件文本行

    paste 命令的功能正好与 cut 相反。它会添加一个或多个文本列到文件中,而不是从文件中抽取文本列。
    它通过读取多个文件,然后把每个文件中的字段整合成单个文本流,输入到标准输出。

    join 基于某个共享字段来联合两个文件的文本行

    一个 join 操作通常与关系型数据库有关联,在关系型数据库中来自多个享有共同关键域的表格的数据结合起来,得到一个期望的结果。

    默认情况下,join 命令使用空白字符做为输入字段的界定符,一个空格作为输出字段的界定符。这种行为可以通过指定的选项来修改。

    比较文本

    comm 逐行比较两个有序的文件

    comm 程序会比较两个文本文件,并且会显示每个文件特有的文本行和共有的文本行。

    • comm 命令产生三列输出。第一列包含第一个文件独有的文本行;第二列文本行是第二列独有的;第三列包含两个文件共有的文本行。
    • -n 选项,这里 n 代表 1,2 或 3。这些选项使用的时候,指定了要隐藏的列。
    # 只显示两个文件共有的行
    $ comm -12 file1.txt file2.txt
    

    diff 逐行比较文件

    diff 程序被用来监测文件之间的差异。然而,diff 是一款更加复杂的工具,它支持许多输出格式,并且一次能处理许多文本文件。软件开发员经常使用 diff 程序来检查不同程序源码版本之间的更改,diff 能够递归地检查源码目录,经常称之为源码树。diff 程序的一个常见用例是创建 diff 文件或者补丁,它会被其它程序使用,例如 patch 程序,来把文件从一个版本转换为另一个版本。

    diff 更改命令 说明
    r1ar2 把第二个文件中位置 r2 处的文件行添加到第一个文件中的 r1 处。
    r1cr2 用第二个文件中位置 r2 处的文本行更改(替代)位置 r1 处的文本行。
    r1dr2 删除第一个文件中位置 r1 处的文本行,这些文本行将会出现在第二个文件中位置 r2 处。
    diff 统一模式更改指示符 含义
    空格 两个文件都包含这一行。
    - 在第一个文件中删除这一行。
    + 添加这一行到第一个文件中。

    patch 逐行比较文件

    patch 程序被用来把更改应用到文本文件中。它接受从 diff 程序的输出,并且通常被用来把较老的文件版本转变为较新的文件版本。

    使用 diff/patch 组合提供了两个重大优点:

    1. 与整个源码树的大小相比较而言,一个 diff 文件非常小。
    2. 一个 diff 文件简洁地显示了所做的修改,从而允许程序补丁的审阅者能快速地评估它。

    运行时编辑

    使用非交互式的方法来编辑文本。例如:通过单个命令把一系列修改应用到多个文件中。

    tr 翻译或删除字符

    tr 程序被用来更改字符。可以把它看作是一种基于字符的查找和替换操作。

    示例:

    # 小写转大写
    $ echo "lowercase letters" | tr a-z A-Z
    LOWERCASE LETTERS
    
    # 查看 tr 命令所支持地完整的转义序列和字符类别列表
    $ tr --help
    

    tr 命令接受两个参数:要被转换的字符集以及相对应的转换后的字符集。字符集可以用三种方式来表示:

    1. 一个枚举列表。例如,ABCDEFGHIJKLMNOPQRSTUVWXYZ。
    2. 一个字符域。例如,A-Z 。注意这种方法有时候面临与其它命令相同的问题,归因于语系的排序规则,因此应该谨慎使用。
    3. POSIX 字符类。例如,[:upper:]。

    大多数情况下,两个字符集应该长度相同;然而,有可能第一个集合大于第二个,尤其如果我们想要把多个字符转换为单个字符

    # 
    $ echo "lowercase letters" | tr [:lower:] A
    AAAAAAAAA AAAAAAA
    

    除了换字之外,tr 命令能允许字符从输入流中简单地被删除。

    # MS-DOS 文本文件转换为为 Unix 文本文件时。需要删除每行末尾的回车符。
    # dos_file 是需要被转换的文件
    # unix_file 是转换后的文件
    $ tr -d '\r' < dos_file > unix_file
    
    # 使用 - s 选项,tr 命令能 “挤压”(删除)相邻的重复的字符实例:
    $ echo "aaabbbccc" | tr -s ab
    abccc
    

    sed 用于筛选和转换文本的流编辑器

    • sed 是 stream editor(流编辑器)的简称,它对文本流进行编辑。
    • sed 是一款强大的,并且有些复杂的程序(有整本内容都是关于 sed 程序的书籍)。
    • sed 的工作方式是要不给出单个编辑命令(在命令行中)要不就是包含多个命令的脚本文件名,然后它就按行来执行这些命令。

    格式:sed 's/regexp/replacement/' file...

    # 将 front 替换为 back
    # s:替换命令
    $ echo "front" | sed 's/front/back/'
    back
    
    sed 地址表示法 说明
    n 行号,n 是一个正整数。
    $ 最后一行。
    /regexp/ 所有匹配一个 POSIX 基本正则表达式的文本行。注意正则表达式通过 斜杠字符界定。选择性地,这个正则表达式可能由一个备用字符界定,通过 \ cregexpc 来 指定表达式,这里 c 就是一个备用的字符。
    addr1,addr2 从 addr1 到 addr2 范围内的文本行,包含地址 addr2 在内。地址可能是上述任意 单独的地址形式。
    first~step 匹配由数字 first 代表的文本行,然后随后的每个在 step 间隔处的文本行。例如 1~2 是指每个位于偶数行号的文本行,5~5 则指第五行和之后每五行位置的文本行。
    addr1,+n 匹配地址 addr1 和随后的 n 个文本行。
    addr! 匹配所有的文本行,除了 addr 之外,addr 可能是上述任意的地址形式。
    sed 基本编辑命令 说明
    = 输出当前的行号。
    a 在当前行之后追加文本。
    d 删除当前行。
    i 在当前行之前插入文本。
    p 打印当前行。默认情况下,sed 程序打印每一行,并且只是编辑文件中匹配 指定地址的文本行。通过指定 - n 选项,这个默认的行为能够被忽略。
    q 退出 sed,不再处理更多的文本行。如果不指定 - n 选项,输出当前行。
    Q 退出 sed,不再处理更多的文本行。
    s/regexp/replacement/ 只要找到一个 regexp 匹配项,就替换为 replacement 的内容。 replacement 可能包括特殊字符 &,其等价于由 regexp 匹配的文本。另外, replacement 可能包含序列 \1 到 \9,其是 regexp 中相对应的子表达式的内容。更多信息,查看 下面 back references 部分的讨论。在 replacement 末尾的斜杠之后,可以指定一个 可选的标志,来修改 s 命令的行为。
    y/set1/set2 执行字符转写操作,通过把 set1 中的字符转变为相对应的 set2 中的字符。 注意不同于 tr 程序,sed 要求两个字符集合具有相同的长度。

    喜欢 sed 的人们也会喜欢。。。

    sed 是一款非常强大的程序,它能够针对文本流完成相当复杂的编辑任务。它最常用于简单的行任务,而不是长长的脚本。
    许多用户喜欢使用其它工具,来执行较大的工作。 在这些工具中最著名的是 awkperl。它们不仅仅是工具,像这里介绍的程序,且延伸到完整的编程语言领域。
    特别是 perl,经常被用来代替 shell 脚本,来完成许多系统管理任务,同时它也是一款非常流行网络开发语言。
    awk 更专用一些。其具体优点是其操作表格数据的能力。awk 程序通常逐行处理文本文件,这点类似于 sedawk 使用了一种方案,其与 sed 中地址之后跟随编辑命令的概念相似。
    虽然关于 awkperl 的内容都超出了本书所讨论的范围, 但是对于 Linux 命令行用户来说,它们都是非常好的技能。

    aspell 交互式拼写检查器

    aspell 是一款交互式的拼写检查器。

    拼写检查一个包含简单的文本文件:

    $ aspell check textfile
    

    示例:

    # 生成带错误单词的文件
    $ cat > foo.txt
    The queck brown fox jimped over the laxy dog.
    
    # 交互式拼写检查
    $ aspell check foo.txt
    
    # 拼写可疑且高亮显示的单词,下方会有提示符
    1) quack                                                            6) QC
    2) quick                                                            7) Que
    3) Keck                                                             8) gecko
    4) quark                                                            9) kick
    5) quirk                                                            0) quake
    i) Ignore                                                           I) Ignore all
    r) Replace                                                          R) Replace all
    a) Add                                                              l) Add Lower
    b) Abort                                                            x) Exit
    

    除非由命令行选项 --dont-backup 告诉 aspell,否则通过追加扩展名 .bak 到文件名中, aspell 会创建一个包含原始文本的备份文件。

    -rw-r--r--  1 root    root        45 Jan 19 17:26 foo.txt
    -rw-r--r--  1 root    root        46 Jan 19 17:24 foo.txt.bak
    

    aspell 会认为 HTML 标志的内容是拼写错误。通过包含 -H(HTML)检查模式选项,这个问题能够解决:

    # 检查 HTML 文件:
    $ aspell -H check foo.txt
    

    注意:默认情况下,aspell 会忽略文本中 URL 和电子邮件地址。通过命令行选项,可以重写此行为。也有可能指定哪些标志进行检查及跳过。

    其他操作命令

    一些有趣的文本操作命令也非常值得研究。如:split(把文件分割成碎片), csplit(基于上下文把文件分割成碎片),和 sdiff(并排合并文件差异)。

    相关文章

      网友评论

          本文标题:19. 文本处理

          本文链接:https://www.haomeiwen.com/subject/cxivsqtx.html