Linux文本处理工具

8. Linux文本处理工具

8.1 概述

​ 纯文本(plain text)文件是计算机保存信息的一种基本形式,所谓纯文本文件是指文件全部由人们可以阅读和理解的可打印字符组成,只是简单存储这些字符的编码,而不保存各种控制信息(例如显示内容的字体、字号等),直观理解纯文本文件与其他文件的区别,可以对比使用Windows下“记事本”编辑的文件和使用“Word”编辑的文件。

​ 纯文本文件有着广泛的用途,例如编程时源代码一般保存在纯文本文件中,很多配置信息保存在纯文本文件中,后面要介绍的shell脚本文件是纯文本的,命令行界面中执行特定命令产出的输出也是纯文本的,借助与Linux的输入输出重定向和管道处理机制,针对纯文本的处理工具软件可以在命令行灵活组合,得到用户想要的效果。因此Linux提供了大量的文本处理工具软件,可以粗略地划分为以下几类:

  • 文本编辑:如gedit、vi、nano等,属于独立内容,此处不详细介绍;
  • 文本查看和统计:简单的文本查看工具如cat、more、less等,可以查看文本特定部分的head、tail,用于统计文本信息的wc等;
  • 文本搜索:grep;
  • 文本排序:sort和uniq;
  • 文本提取和合并:cut和paste;
  • 文件比较:diff;
  • 文本转换:tr。

8.2 文本查看和统计

8.2.1 文本查看

cat、more、less是几个基本的文本查看命令,在前面基本操作介绍中都已有涉及。这几个命令的选项不再介绍,只要掌握如下最基本的用途:

  • cat命令:从头开始显示文件内容;
  • more命令:单向分页显示文件内容(只能向后翻页);
  • less命令:分页显示文件内容(可以向前翻页)。
  1. head命令:用于显示文件的头部内容,默认显示头10行。

    #命令格式:
    head [选项和参数]... [文件]...
    

    选项和参数:

    • -q 隐藏文件名
    • -v 显示文件名
    • -c<字节> 显示字节数
    • -n<行数> 显示的行数

    其中行数和字节数:

    • 可以是一个正整数,表示要显示从文件头开始的字节数或行数;
    • 也可以在数值前加“-”,表示要显示文件尾部相应字节数或行数之前的内容。
  2. tail命令用于显示文件的尾部内容,默认显示最后10行。

    #命令格式:
    tail [选项和参数]... [文件]...
    

    选项和参数:

    • -q 隐藏文件名
    • -v 显示文件名
    • -c<字节> 显示字节数
    • -n<行数> 显示的行数

    其中行数和字节数:

    • 可以是一个正整数,表示要显示文件尾部的字节数或行数;

    • 也可以在数值前加“+”,表示要显示从文件头开始相应字节数或行数之后的内容。

8.2.2 统计工具

wc命令用于:统计文本信息,可以统计字节数、字数、行数等。

#命令格式:
wc [选项和参数]文件...

选项和参数:

  • -c 统计字节数;
  • -l 统计行数;
  • -m 统计字符数:与字节数区别在于一个字符可能有多个字节;不能与 -c 选项一起使用。
  • -w 统计字数:一个字(英文单词)被定义为由空白符分隔的字符串。

8.3 文本搜索:grep

​ grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行在标准输出打印出来。

​ grep全称是Global Regular Expression Print,在一个或多个文件中搜索字符串模式(pattern),如果模式串中包括空格,则必须加引号,模式串后的所有字符串被看作文件名。

​ grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索的状态。如果模式搜索成功,则返回0;如果搜索不成功,则返回1;如果搜索的文件不存在,则返回2;利用这些返回值就可进行一些自动化的文本处理工作。

8.3.1 grep命令

#命令格式:
grep [option] pattern file

选项和参数:

  • -c或--count :计算符合模式的行数。
  • -C<显示行数>或--context=<显示行数> :除了显示符合模式的那一行之外,并显示该行之前之后的内容。
  • -h或--no-filename :在显示符合模式的那一行之前不标示所属的文件名称。
  • -H或--with-filename :在显示符合模式的那一行之前标示所属的文件名称。
  • -i或--ignore-cas :忽略字符大小写的差别。
  • -l或--file-with-matches :列出文件内容符合指定的模式的文件名称。
  • -L或--files-without-match :列出文件内容不符合指定的模式的文件名称。
  • -n或--line-number :在显示符合模式的那一行之前标示出行号。
  • -q或--quiet或--silent :不显示任何信息,一般用于shell脚本中调用。
  • -r或--recursive :递归查找子目录。
  • -w或--word-regexp :只显示全字符合的列。

使用grep命令的简单例子如下所示,该命令在/etc/sysconfig目录下递归搜索所有文件,查找包含eth0的行。

grep -r eth0 /etc/sysconfig 2> /dev/null
img

8.3.2 正则表达式

​ 正则表达式使用一个模式字符串来描述、匹配一系列符合某种规则的字符串,通常被用来检索、替换那些符合某个模式的文本,有着广泛的用途,例如在大多数脚本语言中都支持正则表达式的应用。grep是最早应用正则表达式的工具之一,并且是正则表达式得以普及的重要原因。

  1. 基本语法

    正则表达式是一个符合特定语法格式的字符串,其基本语法规则可以表述为:

    {字符类[重复次数]} 
    
    #其中[]和{}不是实际符号,[]表述可选,{}表示任意次重复。
    
  2. 字符类

    常见字符类表示方法包括:

    • 常规字符:匹配字符本身,如:'A'匹配A,'a'匹配a。

    • 通配符号

      • . 匹配一个非换行符的字符 如:'gr.p'匹配gr后接一个任意字符,然后是p。
      • [] 匹配一个指定范围内的字符,如'[Gg]rep'匹配Grep和grep。
      • [^] 匹配一个不在指定范围内的字符,如:[^A-FH-Z]rep匹配不包含A-F和H-Z的一个字母开头,紧跟rep。
      • \w 匹配文字和数字字符,也就是[A-Za-z0-9],如:'G\wp'匹配以G后跟一个文字或数字字符,然后是p。
      • \W \w的反置形式,匹配一个或多个非单词字符,如点号句号等。
    • 锚定符号

      • ^ 锚定行的开始 如:'^grep'匹配所有以grep开头的行。
      • $ 锚定行的结束 如:'grep$'匹配所有以grep结尾的行。
      • \< 锚定单词的开始,如:'<grep'匹配包含以grep开头的单词的行。
      • \> 锚定单词的结束,如'grep>'匹配包含以grep结尾的单词的行。
    • 另外,与字符类相关的还有一些其他有特殊含义的符号:

      • () 字符分组,分组中的串一起被后面的重复次数所修饰。
      • (|) 可替换的字符分组,|分隔的串是“或”的关系。
      • \ 转义符,允许或禁用后面字符的特殊含义,如:'.'匹配任意字符,'.'匹配.字符;'w'匹配w,'\w'匹配任意文字和数字字符。
  3. 重复次数

    • ? 匹配零个或一个先前字符,如:'ab?c'匹配ac或abc。
    • * 匹配零个或多个先前字符,如:'a.*c'匹配a后面有零个或多个任意字符,然后c。
    • + 匹配一个或多个先前字符,如:'a.+c'匹配a后面有一个或多个任意字符,然后c。
    • {m} 重复先前字符m次,如:'a{5}'匹配aaaaa。
    • {m,} 重复先前字符至少m次,如:'a{5,}'匹配至少5个a。
    • {m,n} 重复至少字符至少m次,不多于n次,如:'a{5,10}'匹配5至10个a。

示例:

  1. 显示‘netstat -tan’命令结果中以‘LISTEN’后跟0个、1个或多个空白字符结尾的行:

    netstat -tan | grep -n "LISTEN[[:space:]]*$"
    
  2. 显示/etc/passwd文件中以bash结尾的行:

    grep -n 'bash$' /etc/passwd
    
  3. 显示/etc/passwd文件中的两位数或三位数:

    grep -n '[[:digit:]]\{2,3\}' /etc/passwd
    
  4. 添加用户bash, testbash, basher以及nologin用户(nologin用户的shell为/sbin/nologin),而后找出/etc/passwd文件中用户名同shell名的行:

    grep -n '^\b[[:alnum:]]{1,}\b
    
  5. 显示当前系统上root、centos或user1用户的默认的shell和UID:

    egrep '^\b(root|centos|user1)\b' /etc/passwd |cut -d: -f3,7
    
  6. 找出/etc/rc.d/init.d/functions文件中某单词(单词中间可以存在下划线)后面跟着一组小括号的行:

    grep -n --color '^(\b(\w{1,})\b)' /etc/rc.d/init.d/functions
    
  7. 使用echo输出一个路径,而后egrep找出其路径基名,进一步地使用egrep取出其目录名:

    [root@www ~]# echo /etc/sysconfig/network/ | egrep  -o --color  '[[:alpha:]]+/?$' |cut -d/ -f1
    network
    [root@www ~]# echo /etc/sysconfig/network/ | egrep  -o --color  '^(/)\b.*\1\b' 
    /etc/sysconfig/
    [root@www ~]# echo /etc/sysconfig/network/ | egrep  -o --color  '^(/)\b.*\1\b' |cut -d/ -f1-3
    
  8. 找出ifconfig命令执行结果中1-255之间的数字:

    ifconfig | egrep --color '\b([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b'
    

8.4 文本排序:sort和uniq

对文本内容重新排序是常见需求,Linux下的

  • sort命令提供灵活的按行的排序功能,
  • uniq命令则是检查并处理文本文件中的重复行,经常与sort命令连用。

8.4.1 sort命令

默认情况下sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出,实际可以通过命令行选项改变排序的依据和行为。

#命令格式:
sort [选项和参数] [文件]

选项和参数:

  • -b 忽略每行前面开始出的空格字符。
  • -d 排序时,处理英文字母、数字及空格字符外,忽略其他的字符。
  • -f 排序时,将小写字母视为大写字母。
  • -n 依照数值的大小排序。
  • -r 以相反的顺序来排序。
  • -t<分隔字符> 指定排序时所用的栏位分隔字符,默认是空白符。
  • k<栏位> 以指定的栏位来排序。
  • -o<输出文件> 将排序后的结果存入指定的文件。

例如:对ps命令的输出结果进行排序,按照进程虚存(第五栏位)大小数值倒序排列。

ps aux --noheader | sort -k5 -nr  | head

img

8.4.2 uniq命令

uniq命令检查重复行时,要求重复行必须相邻,因此其输入文件首先要经过排序,一般uniq都会与sort连用。

#命令格式:
uniq [选项和参数] [输入文件] [输出文件]

选项和参数:

  • -c或--count 在每列旁边显示该行重复出现的次数。
  • -d或--repeated 仅显示重复出现的行列。
  • -f<栏位>或--skip-fields=<栏位> 忽略比较指定的栏位。
  • -s<字符位置>或--skip-chars=<字符位置> 忽略比较指定的字符。
  • -u或--unique 仅显示出一次的行列。
  • -w<字符位置>或--check-chars=<字符位置> 指定要比较的字符。

联合使用sort和uniq命令的例子:ps命令只输出进程创建用户,这样会有很多重复行,排序后利用uniq显示重复行数即可确定各个用户创建的进程数目。

ps -e -o user --noheader | sort | uniq -c | sort -rn

img

8.5 文本提取和合并:cut和paste

Linux下有很多命令会产生多列的输出,对其中特定列内容的提取和合并是很常见需求:

  • cut命令用于提取列,
  • paste用于合并列。

8.5.1 cut命令

#命令格式:
cut [选项和参数] [文件]

选项和参数:

  • -b list :按照list指定范围提取字节(byte)
    • -b参数使用较少
  • -c list : 按照list指定范围提取字符(character),适用于规则填充的文本。
  • -f list :按照list指定范围提取字段(field)。
  • -d delim 与-f选项连用:指定字段的分隔符,默认是制表符。
  • -s 与-f选项连用:不包括不含分隔符的行(用于去掉注释和标题)。
  • -n:与“-b”选项连用:不分割多字节字符;
  • --complement:补足被选择的字节、字符或字段;
  • --out-delimiter=<字段分隔符>:指定输出内容是的字段分割符;
  • --help:显示指令的帮助信息;
  • --version:显示指令的版本信息。

示例:

  1. 使用-c选项:/proc/interrupts文件内容是使用空格规则填充的,适合按照字符数提取;文件每行中前5个字符是中断号,34字符以后是所属内核模块(不同计算机上可能数值不同),下面命令提取这两部分内容。

    img

  2. 使用-f选项:/etc/passwd文件内容用“:”分隔不同字段,第1个字段是用户名,第7个字段是用户使用的shell,下面命令提取这两部分内容。

img

更多练习:https://www.cnblogs.com/Spiro-K/p/6361646.html

8.5.2 paste命令

粘贴两个不同来源的数据时,

  • 首先需将其分类,并确保两个文件行数相同。
  • paste将按行将不同文件行信息放在一行。
  • 缺省情况下, paste连接时,用空格或tab键分隔新行中不同文本,除非指定-d选项,它将成为域分隔符。
#命令格式:
paste [选项和参数] [文件]...

paste -d -s -file1 file2

选项和参数:

  • -d或--delimiters= :合并时用指定的分隔符取代默认制表符。
  • -s或--serial :按串行而非并行方式合并文件,将每个文件中的所有行合并到一行,然后依次合并下一文件。
  • - 使用标准输入。对输出的列进行设置

示例:

已知文件内容:

#文件: pas1
ID897
ID666
ID982
#文件: pg pas2
P.Jones
S.Round
L.Clip
  1. 基本paste命令将pas1和pas2两文件粘贴成两列:

    #操作
    > paste pas1 pas2
    #结果
    ID897   P.Jones
    ID666   S.Round
    ID982   L.Clip
    
    #通过交换文件名即可指定哪一列先粘:
    > paste pas2 pas1
    #结果
    P.Jones ID897
    S.Round ID666
    L.Clip ID982
    
  2. 选项的使用

    #使用-d选项:用冒号做域分隔符
    > paste -d: pas2 pas1
    #结果
    P.Jones:ID897
    S.Round:ID666
    L.Clip:ID982
    
    #使用-s选项:要合并两行,而不是按行粘贴。下第一行粘贴为ID号,第二行是名字。
    > paste -s pas1 pas2
    #结果
    ID897   ID666   ID982
    P.Jones S.Round L.Clip
    
    #选项(-):对每一个(-),从标准输入中读一次数据。使用空格作域分隔符,以一个6列格式显示目录列表
    > ls /etc | paste -d" " - - - - - -
    #结果
    MANPATH PATH SHLIB_PATH SnmpAgent.d/ TIMEZONE X11/
    acct/
    
    #也可以以一列格式显示输出:
    > ls /etc | paste -d"" -
    #结果
    MANPATH
    PATH
    SHLIB_PATH
    SnmpAgent.d/
    TIMEZONE
    X11/
    acct/
    

8.6 文件比较:diff

​ diff 命令是 linux上非常重要的工具,用于比较文件的内容,特别是比较两个版本不同的文件以找到改动的地方,在命令行中打印每一个行的改动。

​ diff程序的输出被称为补丁 (patch),因为Linux系统中还有一个patch程序,可以根据diff的输出实现源程序的批量更新。diff是svn、cvs、git等版本控制工具不可或缺的一部分。

diff命令能比较单个文件或者目录内容

  • 如果指定比较的是文件,则只有当输入为文本文件时才有效。以逐行的方式,比较文本文件的异同处;
  • 如果指定比较的是目录的的时候,diff 命令会比较两个目录下名字相同的文本文件。列出不同的二进制文件、公共子目录和只在一个目录出现的文件,但不会比较其中子目录。
#命令格式:
diff [选项或参数] [文件1或目录1] [文件2或目录2]

选项和参数:

  • -b或--ignore-space-change 不检查空格字符的不同。
  • -B或--ignore-blank-lines 不检查空白行。
  • -q或--breif 只报告是否不同,不显示细节。
  • -u,-U或--unified= 以合并的方式来显示文件内容的不同。
  • -y或--side-by-side 以并列的方式显示文件的异同之处。
  • -w或--ignore-all-space 忽略全部的空格字符。
  • --left-column 在使用-y参数时,若两个文件某一行内容相同,则仅在左侧的栏位显示该行内容。

diff命令的重要性主要在于是Linux下开源项目的默认补丁工具。

8.7 文本转换:tr

​ tr命令可以对来自标准输入的字符进行替换、压缩和删除。它可以将一组字符变成另一组字符,用于对文本内容进行简单加工。

#命令格式:字符集2:指定要转换成的目标字符集。
tr [选项] 字符集合1 [字符集合2]

#字符集合1:指定要转换或删除的原字符集;
#当执行转换操作时,必须使用字符集合2指定转换的目标字符集;执行删除操作时,不需要字符集合2

选项:

  • -d或- -delete:删除所有属于第一字符集的字符;
  • -s或--squeeze-repeats:把连续重复的字符以单独一个字符表示;

示例:

  1. 转换:

    echo "HELLO WORLD" | tr 'A-Z' 'a-z'
    
    hello world
    
  2. 删除:

    echo "hello 123 world 456" | tr -d '0-9'
    
    hello world
    
posted @ 2024-06-16 18:32  Sunflower0312  阅读(71)  评论(0)    收藏  举报