正则表达式

在讲linux三剑客之前,我们先来了解一下正则表达式。

什么是正则表达式?**正则表达式**,又称规则表达式**,**(Regular Expression,在代码中常简写为regex、regexp或RE),是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"),是[计算机科学](https://baike.baidu.com/item/计算机科学/9132?fromModule=lemma_inlink)的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式(规则)的文本。

基本正则表达式(BRE)

BRE对应元字符有:^ $ . [] *

  • 匹配字符
  • 匹配次数
  • 位置锚定
符号作用
^用于模式最左侧,如“^abcd”,匹配以abcd开头的行
$用于模式最右侧,如“abc$”,匹配以abc结尾的行
^$组合符,表示空行
.匹配任意一个且只有一个字符(任意一个字符),不能匹配空行
\转义字符,例如‘.’表示小数点
*匹配前一个字符0次或1次以上
.*组合符,匹配所有内容
^.*匹配任意多个字符开头的内容
.*$匹配任意多个字符结尾的内容
[abc]匹配[]集合中任意一个字符,a或b或c,可以写[a-c]
[^abc]匹配除了^后面的任意字符

扩展正则表达式

ERE在BRE的基础上,增加上 :() {} ? + |

扩展正则必须使用 grep -E 才能生效

字符作用
+匹配前面字符一次或多次
[ ]+匹配括号内的字符一次或多次
匹配一个字符0次或1次
|表示或者,同时过滤多个字符串
()分组过滤,括号内表示一个整体
a{n,m}表示匹配a(可更换)字符最少n次,最多m次
a{n,}匹配最少n次
a{n}匹配正好n次
a{,m}匹配最多m次

三剑客

  • grep : 文本过滤工具,行过滤
  • sed: 对文件或是数据流进行加工处理,操作,过滤转换文本
  • awk: 格式化文本内容,对文本进行复杂处理

grep与正则表达式:按行匹配

作用:文本搜索工具,根据用户指定的模式对目标文本进行匹配检查,打印匹配到的行

grep [options] [pattern] file

命令 参数 匹配模式 文件

常见的参数:

  1. -i : 忽略大小写
  2. -n:显示匹配行的行号
  3. -c : 只统计匹配的行数
  4. -w:只匹配过滤的单词
  5. -o : 仅显示匹配到的字符串本身(默认整行输出)
  6. -v : 排除匹配结果,显示不能被匹配到的行
  7. -E: 支持使用扩展的正则表达式

案例:

  • grep “root” ./pwd.txt -i: 查找pwd.txt文件中包含root的行

  • grep “^$” space.txt -v:查找space.txt文件中的非空行

  • grep “^$” space.txt -v | grep “^#” -v: 查找文件中的非空行和非#号开头的行
    注意在管道符后面的grep中不需要加文件名

  • grep "\.$" space.txt -n:查找以 . 结尾的行
    注意.符号为匹配任意一个有且只有一个字符,不匹配空行。所以需要用 \ 符号

  • grep ".b" space.txt -n:查找包含"(任意字符)b"格式的行
    可以将. 理解为任意一个字符

  • grep "q*" space.txt -n : 出现q的行,0次1次或多次

  • 贪婪匹配
    grep “.*e” space.txt -n:以e结尾,无论前面是什么

注意只有‘.*’ 是匹配全部

  • [abc]:表示匹配括号中任意一个字符

    1. [a-z] 匹配所有小写单个字母

    2. [A-Z]:匹配所有单个大写字母

    3. [a-zA-Z]:匹配所有单个大小写字母

    4. [0-9]:匹配所有单个数字

    5. [a-zA-Z0-9]:匹配所有数字和字母

    6. 案例:

      - grep "[a-eA-C0-3]" space.txt :匹配a-e和A到C和0-3的字符
      - grep "[^0-3]" space.txt :匹配存在除0-3以外字符的行

扩展正则表达式的使用

使用grep -E进行使用扩展正则

+:匹配前面字符一次或多次

grep -E "i+" pwd.txt:匹配出现i字符一次或多次的行

grep -E "abi+" pwd.txt:匹配出现abi字符一次或多次的行
注意在+号前有多个字符时,将其看为一个整体去匹配

?:匹配前面字符0次或1次

grep -E "go?d" test.txt:匹配g和d之间出现0次或一次o符号的行

|:或

grep -E "a|b" test.txt : 匹配出现字符a或b的行

()
  1. 将括号里面内容当作整体

  2. 括号里面内容可以被后面的 \n 作为正则引用, n 为数字,表示引用第几个符号。

    • \1:表示从左起,第一个括号中模式所匹配到的字符
    • \2:表示从左起,第二个括号中模式所匹配到的字符
  3. 找出包含good和glad 的行

  • grep -E ”good | glad“ test.txt
  • 或者 grep -E "g(oo | la)d" test.txt
  1. 找出 "love .* love "格式的行
    grep -E "(love).*\1": (love) 匹配love,.* 表示任意字长度符,\1表示引用第一个括号中内容
(n,m):匹配次数

grep -E "y{2,4}" test.txt:匹配y字符最少两次最多四次的行

sed与正则表达式

注意sed 和awk使用单引号,双引号有其他特殊解释

sed常用功能包括结合正则表达式对文本实现快速的增删查改,其中查询功能中最常见的两大功能是过滤(过滤指定字符串)取行(取出指定行)
sed详细工作流程:

image-20230130142158923

语法:

sed [选项] [sed内置命令字符] [输入文件]

sed的内置命令用于对文件进行不同的操作功能,例如对文件的增删查改

选项

参数选项解释
-n取消默认sed的输出,常与sed内置命令p一起用
-i直接将修改结果写入文件,不用-i,sed修改的是内存数据
-e多次编辑,不需要管道符了
-r支持正则扩展

sed常用的内置命令字符

sed常用内置命令字符解释
aappend,对文本追加,在指定行后面添加一行/多行文本
ddelete,删除匹配行
iinsert,表示插入文本,在指定行前插入一行/多行文本
pprint,打印匹配行的内容,通常p与-n一起使用
s/正则/替换内容/g匹配正则内容,然后替换内容(支持正则),结尾g代表全局匹配

sed匹配范围

范围解释
空地址全文处理
单地址指定文件某一行
/pattern/被模式匹配到的每一行
范围区间10,20 表示十到二十行;10,+5 表示十行向下五行
步长1~2 表示1,3,5,7,9行;2~2表示2,4,6,8,10行

案例

  1. 输出文件第2,3行
    sed '2,3p' -n test.txt
    p与-n常一起使用,p为print,-n为取消sed默认输出

  2. 过滤出含有linux的字符串行
    sed '/linux/p' -n test.txt
    sed中匹配范围时用/pattern/

  3. 删除有compute的行
    sed '/game/d' test.txt -i
    添加-i参数会直接将修改结果写回文件

  4. 删除第五行到结尾行
    sed '5,$d' test.txt -i

  5. 将文件中全部my替换为his
    sed 's/my/his/g' 1.txt -i
    s/你想找的内容/想替换的内容/全局替换

  6. 替换所有的his为my,同时替换QQ号(多次替换)
    sed -e 's/his/my/g' -e 's/12345/123/g' -i test.txt
    多次替换中必须是-e在前,’s///‘在后

  7. 在文件的第二行下面追加内容"and games"(后面新增一行
    sed '2a and games' -i test.txt

  8. 在文件的第六行前面插入"and games"(前面新增一行
    sed '6i and games' -i test.txt

  9. 在文件的第三行前面插入"and games" ,“123” 两行数据(新增多行
    sed '3i and games\n 123' -i test.txt

  10. 在每一行下面添加 "-----------------"行(空地址)
    sed 'a --------------------' -i test.txt

  11. 取出eth0中ip地址

    image-20230130142715154
  • ifconfig eth0: 取出第一块内容

  • sed '2p' -n:取出第二行内容

  • sed 's/^.*inet//' : inet之前且包含inet的内容替换为空格

  • sed 's/net.*$//' :将net之后且包含net的内容替换为空格

  • 将以上三个步骤用管道符联合或者用-e参数多次编辑

  • 用管道符号:ifconfig eth0 | sed '2p' -n | sed 's/^.*inet// | sed 's/net.*$//'

  • 用-e参数:ifconfig eth0 | sed -e '2s/^.*inet//' -e '2s/net.*$//' -e '2p' -n, 其中,sed '2s///' 表示对第2行进行操作

awk与正则表达式

awk [option] ‘pattern[action] file …’

awk 参数 ’条件动作‘ 文件

action 指的是动作,awk擅长文本格式化,且输出格式化后的结果,因此最常用的动作就是 printprintf

awk '{print $2}' : 没有使用参数和模式,输出文本的第二列信息

  1. $2 表示第二列,$0 表示一整行
  2. awk 默认以空格为分隔符,且多个空格视为一个空格
  3. awk 是按行处理文件,一行处理完处理下一行
  4. $NF表示当前分割的最后一列,倒数第二列可以写成$(NF-1)
image-20230130143005920

awk 内置变量

内置变量解释
$n指定分隔符后,当前记录的第n个字段
$0整行
FS字段分隔符,默认为空格
OFS输出字段分隔符,默认为空格
RS指定输入时的换行符
ORS指定输出时的换行符
NF分割后,当前一共有多少字段
NR行号
FNR各文件分别计数的行号
FILENAME当前文件名
ARGC命令行参数的个数
ARGV数组,保存的是命令行所给定的各参数

awk 功能参数

参数解释
-F指定分隔符
-v定义或修改一个awk内部的变量,如NF,FS
-f从脚本文件中读取awk命令

案例

  1. 一次性输出多列

    awk '{print $1,$2,$5}' test.txt

    • 如果为$1$2$5 则输出没有空格
    • 可以自定义列顺序,例如:$5,$3,$1,则输出的列也会相应排列
  2. 自定义输出内容
    awk必须外层单引号,内层双引号
    内置变量 $1 、$2 都不得添加双引号,否则会识别为文本

  3. 取出文件第五行
    NR在awk中表示行号,NR==5表示行号为5的那一行
    awk 'NR==5{print $0}' test.txt
    其中NR==5表示模式,即选择的行区域;{print $0}表示动作

  4. 取出多行文件
    awk 'NR==3,NR==10{print $0} test.txt':表示整行取出从第3行到第10行内容

  5. 增添行号:使用内置变量
    awk '{print NR,$0}' test.txt: NR为内置变量,使用不需要加$

  6. 输出37到40行内容并加上行号
    awk 'NR==37,NR==40{print NR,$0}' test.txt

  7. 显示文件的第一列,倒数第二和最后一列
    awk {print $1,$(NF-1),$(NF)} test.txt

  8. 取ip地址
    ifconfig eth0 | awk 'NR==2{print $2}'

分隔符

awk的分隔符有两种:

  • 输入分隔符,默认值为空格,变量名为FS
  • 输出分隔符,简称为OFS
  1. 更改输入分隔符
    使用其他分隔符,如#号:awk -F '#' '{print $1,$NF}' pwd.txt
    或者使用更改变量参数:awk -v FS='#' '{print $1,$NF}'

  2. 更改输出分隔符
    awk执行完命令,默认用空格隔开每一列,这个空格即为awk的默认输出符
    awk -F '#' -v OFS='---' '{print $1,$NF}' pwd.txt

awk变量

  1. FNR变量

    • awk ’{print NR,$1}‘ pwd.txt test.txt:普通的NR变量会将多个文件按照文件顺序排序
    • awk '{print FNR,$1}' pwd.txt test.txt: FNR变量,将会分别对文件进行计数
  2. RS(输入分隔符)和ORS(输出分隔符)变量

  • awk -v RS=' ' '{print NR,$0}' test.txt: 见到空格就换行
  • awk -v ORS='--------\n' '{print NR,$0}' test.txt:将--------添加至每行结尾
  1. FILENAME变量(当前文件名称)
    awk -F ':' '{print FILENAME,NR,$0}' pwd.txt

  2. 变量ARGC、ARGV
    ARGV表示一个数组,数组中保存的是命令行给的参数
    awk 'BEGIN{print "开始使用wak"}{print ARGV[0],ARGV[1],ARGV[2]}' pwd.txt test.txt:先执行BEGIN中的内容

  3. 自定义变量

    • awk -v myname="tanging" 'BEGIN{print "my name is ",myname}'

    • 间接引用shell变量

      1
      2
      myname=“yuanyuan”
      awk -v awk_myname=$myname 'BEGIN{print awk_myname}'

awk格式化

printf格式化输出

printf与print的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
format的使用

要点:
1. printf要指定format
2. format用于指定后面的每个item的输出格式
3. printf语句不会自动打印换行符

format格式的指示符都以%开头,后跟一个字符,如下:
%c : 显示字符的ASCII码
%d,%i : 十进制整数
%e,%E : 科学计数法显示数值
%f : 显示浮点数
%g,%G : 以科学家计数法的格式或浮点数的格式显示数值
%s : 显示字符串
%u : 无符号整数
%% : 显示%自身

printf修饰符:
- : 左对齐;默认为右对齐
+ : 显示数值正负符号;例如 printf "%+d" :十进制整数的正负显示
给printf添加格式
  • 格式化字符串 %S 代表字符串的意思
    awk ’{printf "%s\n,$1"}‘ pwd.txt
  • 例子:对pwd.txt文件进行格式化
1
2
3
awk -F ':' 'BEGIN{printf "%-25s\t%-25s\t%-25s\n","用户名","密码","UID"}{printf "%-25s\t%-25s\t%-25s\n",$1,$2,$3}' pwd.txt
# 参数解释
# %-25s : -代表左对齐,25为总共字符长度

awk模式

awk语法:

awk [option] ‘pattern[action] file’

  1. 特殊的pattern : BEGINEND
  • BEGIN模式是处理文本之前需要执行的操作
  • END模式是处理完所有行之后要执行的操作
1
awk -F ':' 'BEGIN{print "处理前"}{print $1}END{print "处理后"}' pwd.txt
  1. awk模式pattern也可以理解为条件,不指定任何模式则默认按行处理,如果指定了模式则只有符合模式的才会被处理
关系运算符解释
<小于
<=小于等于
==等于
!=不等于
>=大于等于
>大于
~匹配正则
!~不匹配正则
  1. awk模式总结
  • 空模式,没有指定任何模式,按行运行
    awk '{print $0}' pwd.txt

  • 关系运算符模式
    awk 'NR==2,NR==5{print $0}' pwd.txt:读取第二行到第五行内容

  • BEGIN/END模式
    awk -F ':' 'BEGIN{print "处理前"}{print $1}END{print "处理后"}' pwd.txt

awk与正则表达式

正则表达式主要与awk的pattern模式结合使用

awk使用正则语法

awk '/正则表达式/动作' file : awk命令使用正则表达式,必须把正则放入’//'双斜杠中

  • awk命令执行流程
    awk 'BEGIN{commands} pattern{commands} END{commands}'

    1. 优先执行 BEGIN{}中的语句
    2. 根据模式pattern执行commands
    3. 执行END{}中命令
  • 筛选pwd.txt文件中有root开头的行的第一列和最后一列
    awk -F ':' '/^root/{print $1,$NF}' pwd.txt

  • 筛选pwd.txt文件中以/sbin/nologin结尾的行
    awk -F ':' '/\/sbin\/nologin$/{print $0}' pwd.txt:添加转义符

  • 找出文件的区间内容
    正则模式: awk '/正则表达式/{动作}/ file'
    行范围模式: awk '/正则1/,/正则2/{动作}' file:第一个正则为提取行首,第二个正则为提取行尾
    1. 找出mail用户到nobody用户之间的内容
      awk '/^mail/,/^nobody/{print $0}' pwd.txt
    2. 统计访客数量
      awk '{print $1}' access.log | sort -n | uniq | wc -l
    3. 找出访问最频繁的前十个ip
      awk '{print $1}' access.log | sort -n | uniq -c | sort -nr | head -10