文本处理工具和正则表达式

一、文本处理工具

1.文件查看:cat,more,less

1.1 cat,tac,nl,rev

cat [OPTION]…[FILE]…

  • -E: 显示行结束符$
  • -n:对显示出的每一行编号
  • -A:显示所有控制符
  • -b:非空行编号
  • -s:压缩连续的空行成一行

tac : 与cat显示结果相反(最后一行放在最前)

nl:相当于cat -b 空行不加行号

rev: 每一行中的字符倒序显示

1.2 more与less,分页显示

都可以分页显示,都是空格/回车往下翻,b键往前翻。区别在于:more命令翻到底会自动退出来,less翻到底不会自动退出来(man帮助就用的less)

2.文件截取:head,tail

2.1 head

head [option] [file]

  • -c 指定获取前#字节

    此命令可用于取随机口令:

    1
    [root@centos8 ~]#tr -dc '[:alnum:]' < /dev/urandom | head -c10

    tr -dc ‘[:alnum:]’ : 用tr命令删除随机字符中的非字母非数字的字符,d是删除,c是取反

    head -c10:取10位

  • -n 指定获取前#行

  • -# 指定行数

tail [option] [file]

  • -c 指定获取后#字节
  • -n 指定获取后#行
  • -# 指定行数(表示最后的几行)
  • -f 跟踪显示文件新追加的内容,常用于日志监控,相当于–follow=descriptor
  • -F 跟踪文件名,相当于–follow=name –retry

tailf 类似于tail -f,当文件不增长时并不访问文件

3.按列抽取:cut和paste

3.1cut [OPTION] [FILE]
  • -d 指明分隔符,默认为tab

  • -f FILEDS:

    • #:第#个字段

    • #,#: 离散的多个字段,例如:1,3,6

    • #-#:连续的多个字段,例如1-6

      混合使用:1-3,7

  • -c 按字符切割

  • –output-delimiter=STRING 指定输出分隔符

    例如:

    1
    [root@centos8 ~]#cut -d: -f1,3 /etc/passwd

    以:为分隔符,取出/etc/passwd文件中的第1和第3字段

    应用:取ip地址:

    1
    [root@centos8 ~]#ifconfig eth0 | head -2 | tail -1|tr -s " "|cut -d " " -f3

    tr -s “ “: 压缩空格

    cut -d “ “:以空格作为分隔符

    应用:df取利用率

    1
    [root@centos8 ~]#df | cut -c44-46| tr -dc '[0-9\n]'

    cut -c44-46 : 通过数字符(xshell复制时可以显示),直接取出第44-46个字符

    tr -dc ‘[0-9\n]’ : 删除掉除了数字和换行以外的字符

3.2paste合并两个文件同行号的列到一列

pasete [OPTION] [FILE]

  • -d分隔符:指定分隔符,默认用tab(即用分隔符来分隔合并进来的两列)
  • -s:所有行合成一行显示(相当于转置了)

4.排序和统计:sort,wc

4.1收集文本统计数据wc

计算单词总数、总行数、字节总数和字符总数

可以对文件或STDIN中的数据运行

wc story.txt

39 237 1901

行数 字数 字节数

  • -l 只计数行数
  • -w 只计数单词数
  • -c 只计数字节总数
  • -m 只计数字符总数
  • -L 显示文件中最长行的长度
4.2 文本排序sort,去重uniq

sort [OPTION] file(s)

  • -r :逆序排序
  • -R:随机顺序
  • -n:执行时按数字大小整理
  • -f:忽略字符串中的字符大小写
  • -u:删除输出中的重复行
  • -t c :使用c作为字段界定符(相当于cut中的d)
  • -k X:是用c字符分割的X列来整理能够使用多次(相当于cut中的f)

例如,将用户按uid从小到大来排序

1
[root@centos8 ~]#getent passwd | sort -t: -k3 -n

uniq:从输入中删除前后相接的重复的行

uniq [OPTION] [FILES]

  • -c:显示每行重复出现的次数

  • -d:仅显示重复过的行

  • -u:仅显示不曾重复的行

    注意:连续且完全相同方为重复

  • 常与sort一起配合使用(先用sort排序使得一样的行相邻),比如

  • [root@centos8 ~]#cut -d" " -f1 /var/log/httpd/access_log|sort|uniq -c |sort -nr
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44

    上例可以通过分析httpd的日志文件查看发起访问的ip最多的是哪个

    **diff 比较两个文件的不同**

    diff file1 file2

    可以将比较得出的差异生成一个文件,再用patch命令在原来文件的基础上来打补丁,例如:

    ```bash
    [root@centos8 test]#cat a.txt
    a
    b
    c
    [root@centos8 test]#cat b.txt
    a
    bb
    ccc
    dddd
    [root@centos8 test]#diff -u a.txt b.txt
    --- a.txt 2023-03-12 11:10:44.276114540 +0800
    +++ b.txt 2023-03-12 11:11:08.163115724 +0800
    @@ -1,3 +1,4 @@
    a 两个文件一样的行
    -b 意思是在a.txt的基上减去b就能和b.txt一样
    -c 意思是在a.txt的基上减去c就能和b.txt一样
    +bb 意思是在a.txt的基上加上bb就能和b.txt一样
    +ccc 意思是在a.txt的基上加上ccc就能和b.txt一样
    +dddd 意思是在a.txt的基上加上dddd就能和b.txt一样
    [root@centos8 test]#diff -u a.txt b.txt > diff.log
    [root@centos8 test]#patch -b a.txt diff.log
    此处的-b是对原来的a.txt做个备份,如果不加的话,原来的a.txt就会直接被新文件替代
    patching file a.txt
    [root@centos8 test]#ls
    a.txt a.txt.orig b.txt diff.log
    [root@centos8 test]#cat a.txt.orig
    a
    b
    c
    [root@centos8 test]#cat a.txt
    a
    bb
    ccc
    dddd

5.文本过滤:grep

grep [OPTION] PATTERN [FILE…]

例如:

grep root /etc/passwd

grep “$USER” /etc/passwd

grep ‘$USER’ /etc/passwd

grep `whoami` /etc/passwd

grep 的选项:

  • –color=auto 对匹配到的文本着色显示(默认,因为系统中的grep实际用的是别名,alias grep=’grep –color=auto’)

  • m # 匹配#次后停止

  • -v 显示不被匹配到的行

  • -i 忽略字符大小写

  • -n 显示匹配到的行号

  • -c 统计匹配的行数

  • -o 仅显示匹配到的字符串

  • -q 静默模式,不输出任何信息

  • -A # after,后#行(有时想看到包含匹配内容的后续行时有用,下同)

    例如:

    1
    2
    3
    4
    5
    [root@centos8 test]#grep -iA3 ROOT /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
  • -B # before,后#行

  • -C # context,前后各#行

  • -e 实现多个选项间的逻辑or关系

  • -w 匹配整个单词(注意:所谓单词指字母、数字、下划线组成的一个词)

  • -E 使用ERE

  • -F 相当于fgrep,不支持正则表达式

  • -f file 根据模式文件处理

二、正则表达式

REGEXP: Regular Expressions,由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)不表示字符字面意义,而表示控制或通配的功能

  • 程序支持:grep,awk,sed,vim,less,nginx,varnish等

  • 分两类:

    • 基本正则表达式 BRE
    • 扩展正则表达式 ERE
      • grep -E,egrep
  • 正则表达式引擎:采用不同算法,检查处理正则表达式的软件模块

  • 元字符分类:字符匹配、匹配次数、位置锚定、分组

  • man 7 regex

1.字符匹配类元字符:

  • . 匹配任意单个字符

  • [] 匹配指定范围内的任意单个字符,如 [nanyu] [0-9] [a-z] [a-zA-Z]

  • [^]匹配指定范围外的任意单个字符

  • [:alnum:] 字母和数字

  • [:alpha:] 代表任意字母,即A-Z,a-z

  • [:lower:] 小写字母

  • [:upper:] 大写字母

  • [:blank:] 空白字符(空格和制表符)

  • [:space:] 水平和垂直的空白字符(比[:blank:] 包含范围更广)

  • [:cntrl:] 不可打印的控制字符(退格、删除、警铃等)

  • [:digit:] 十进制数字

  • [:xdigit:] 十六进制数字

  • [:graph:] 可打印的非空白字符

  • [:print:] 可打印字符

  • [:punct:] 标点符号

    例如:

    [horay] 代表h,o,r,a,y之中的任意字符

    [^horay] 代表不属于h,o,r,a,y之中的任意字符

    [[:lower:]] 代表任意一个小写字母

2.匹配次数

用在要指定次数的字符后面,用于指定前面的字符要出现的次数

  • *匹配前面的字符任意次,包括0次

    贪婪模式:尽可能长的匹配

  • .* 任意长度的任意字符

  • ? 匹配前面的字符0或1次

  • \+ 匹配前面的字符至少1次

  • \{n\}匹配前面的字符n次

  • \{m,n\}匹配前面的字符至少m次,至多n次

  • \{,n\}匹配前面的字符至多n次

  • \{n,\}匹配前面的字符至少n次

3.位置锚定

  • ^ 行首锚定,用于模式的最左侧

  • $ 行尾锚定,用于模式的最右侧

  • ^PATTERN$ 用于模式匹配整行

    • ^$ 空行
    • ^[[:space:]]*$ 空白行
  • \< 或 \b 词首锚定,用于单词模式的左侧

  • \> 或 \b 词尾锚定,用于单词模式的右侧

  • \<PATTERN\> 匹配整个单词

例如:

过滤出不是以#开头的行

1
[root@centos8 test]#grep ^[^#] /etc/fstab

取出ip地址

1
2
[root@centos8 test]#ifconfig eth0 | grep -o '[0-9.]\{7,15\}'| head -1
10.0.0.101

上例中的’[0-9.]\{7,15\}’ 指的是由数字或.组成的字符最小应该有7位(例如1.1.1.1这样的ip),最长不超过15位(例如111.111.111.111这样的ip)

4.分组表达式

  • 分组:\(\)讲一个或多个字符捆绑在一起,当做一个整体处理

  • 分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这项变量命名方式为:\1, \2 ,\3

  • \1 表示从左侧起第一个括号以及与之匹配右括号之间的模式所匹配到的字符

  • 后向引用:引用前面的分组括号中的模式所匹配字符,而非模式本身

  • 或者:\|

    示例:

    a\|b a或b

    C\|cat C或cat

    \(C|c\)at Cat或cat

例如:下例中将root作为一个分组,分组重复了三次

1
2
[root@centos8 test]#echo rootrootroot | grep "\(root\)\{3\}"
rootrootroot

例题1:找出/etc/passwd中的两位数或三位数

1
[root@centos8 test]#grep -o "\<[0-9]\{2,3\}\>" /etc/passwd

例题2:找出/etc/passwd中用户名和shell同名的行

1
[root@centos8 test]#grep "^\([^:]\+\):.*\<\1$" /etc/passwd

例题3:利用df和grep,取出磁盘各分区利用率,并从小到大排序

方法1:

1
[root@centos8 test]#df | grep "^/dev"|tr -s " " %|cut -d% -f5|sort -n

方法2:

1
[root@centos8 test]#df | grep "^/dev"|grep -o "[0-9]\+%"|tr -d %|sort -n

5.扩展的正则表达式

较基础正则表达式在次数匹配和分组方面少了烦人的:

grep使用时用egrep或者加 -E选项

比如,次数匹配方面:

  • *匹配前面字符任意次
  • ? 0或1次
  • +1次或多次
  • {m} 匹配m次
  • {m,n} 至少m次,最多n次

分组方面:

直接用 ()即可

或者方面:

C|cat C或者cat

(C|c)at Cat或者cat