(1)目的:对文本(字符串)进行过滤、替换(编辑)、格式化等 regular expression
(2) 正则表达式: pattern = 特殊字符 + 文本字符
(3) 正则表达式分类: Basic RE Extend RE
(1) 匹配字符的(单个字符、字符集合、字符范围、字符间的选择)
(2) 匹配次数
(3) 位置锚定
位置锚定:
^ 用于pattern的最左侧,以pattern开头的行
$ 用于pattern的最右侧,以pattern结尾的行
^$ 组合符 表示空行
匹配字符:
[abcd] 匹配[]内任意一个字符等价于===[a-d]
[^abcd] ^在[]内表示取反,匹配除了[]内的所有字符
. 通配符 匹配除换行符 \n 之外的任何单字符
* 通配符所有内容
.* 组合符 匹配所有内容
^.* 组合符 匹配以任意多个字符开头的内容
.*$ 组合符 匹配以任意多个字符结尾的内容
匹配次数:
{n} 匹配出现n次
{n,} 至少匹配出现n次
{n, m} 在[n,m]区间次
+ >= 1次 等价于 {1,}
? <= 1次 等价于 {0, 1}
示例:
^[0-9a-z_-]+{3,15}abc$
## ^为匹配输入字符串的开始位置
## 0-9 a-z _-组合的字符串长度必须在3-15这个区间
## abc$匹配字母 abc 并以 abc 结尾,$ 为匹配输入字符串的结束位置。
1. cut命令-----针对文件或管道----按行处理
测试文本 cut.txt
a_202204110214_10.251.82.225
b_202204110215_10.251.82.223
b_202204110212_10.251.82.226
c_202204110214_10.251.82.228
# 截取第一个字符 第三个字符 a2 b2 b2 c2
cut -b 1,3 cut.txt ## 1,3 表示的是第一个字符、第三个字符 【-b 以字节为单位截取 -c 以字符为单位进行截取】
# 截取3-6这段字符串 2022 2022 2022 2022
cut -b 3-6 cut.txt
# 按分割符划分成几个section 配合-f 取第几个section内容
cut -d _ -f 3 cut.txt ## -d _划分为3个section 取第3个section内容 输出结果:10.251.82.225 10.251.82.223 10.251.82.226 10.251.82.228
#测试文本
AAA:2:13
BBB:80:14
CCC:13:18
DDD:45:11 # 与
EEE:30:17
DDD:45:11
sort -u sort.txt # 排序后删除重复的行
sort -nk 2 -t : sort.txt # -t 排序指定的分隔符 : -n 根据字符串的数字比较(不需要参数) -k 指定需要排序的栏位(列、域)
#测试文本
192.168.0.13
192.168.0.12
23.207.92.222
129.204.222.143
114.114.114.114
114.111.112.114
sort -k1,1n -k2,2n -k3,3n -k4,4n sort.txt # 对第一列、第二列、第三列、第四列进行排序(规则 越前等级越高)
sort的其它选项
-b 忽略每行前的空白区域
-d 只考虑处理空格、字母、数字
-f 忽略字母大小写
-m 合并已经排序的文件 不排序
-o 导出排序结果到文件中
# 测试文本 uniq.txt
dong dong
lai lai
dong dong
shun shun
shun shun
fan fan
fan fan
dian dian
(1) uniq -u uniq.txt # 只显示出现一次的行
输出结果:
dong dong # 不相邻的重复的行 认为是两行
lai lai
dong dong
dian dian
(2)uniq -d uniq.txt # 只显示(相邻)重复的行
输出结果:
shun shun
fan fan
(3)uniq -c uniq.txt # 删除文件中相邻的重复的行 And 显示每行出现的次数
输出结果:
1 dong dong
1 lai lai
1 dong dong
2 shun shun
2 fan fan
1 dian dian
(4)uniq uniq.txt # 不加参数的选项后的输出
dong dong
lai lai
dong dong
shun shun
fan fan
dian dian
wc 统计文件的行数、字节数、单词数
#测试文本 wc.txt
dong dong
lai lai
shun shun
fan fan
dian dian
#不加参数选项
(1) wc wc.txt
5 10 46 cut2.txt # 行数 字数 字节数 文件名
(2) wc -l wc.txt
5 wc.txt # -l 行数
(3) wc -w wc.txt
10 wc.txt # -w 字数
(4) wc -c wc.txt
46 wc.txt # -c 字节数
-c --complement 反选设定字符,选择的不处理,不选的处理
-d 删除指令的指定的字符
-s 将连续的重复的字符缩进成单个字符 baaaaaac ==> bac
(1) 替换字符
echo 'Hello World' | tr 'H' 'h' # 输出 hello World
echo 'Hello World' | tr 'Ho' 'xx' # 输出 xellx Wxrld 将H字符替换为x o字符替换成x
(2) 删除字符
echo 'Hello World 12345' | tr -cd [:digit:] # -c反选 -d 删除 [:digit:] 数字集 即删除除数字外其它字符 输出 12345
echo 'Hello World 12345' | tr -cd [:alpha:] # -c反选 -d 删除 [:alpha:] 字母集 即删除除字母外其它字符 输出 HelloWorld
(3) 压缩字符
echo 'HHHHHHHHelloooooooooooo Woooooooorrrrrrlddd' | tr -s 'Hord' # 压缩的字符是H o r d 输出: Hello World
grep本身是按行输出
格式:
grep [选项] [pattern] file
选项:
-E 支持扩展正则
匹配控制选项:
-i 忽略大小写
-v 反转匹配的pattern
输出选项
-o 只输出查找pattern
-n 输出行号
-c 打印匹配的行数
-l 输出匹配的每一行
示例:
grep -rn "hello,world" /home/itcast 查找 /home/itcast 下包含“hello,world“字符串的文件
grep -a hello /bin/ls 将二进制文件以文本文件的方式搜索 hello
grep -i hello /etc/passwd 在 /etc/passwd 文件里找 hello 并且忽略大小写查找
grep -n hello /etc/passwd 搜索 hello 结果并显示在文件里出现的行号
grep -w hello /etc/passwd 搜索完全匹配 hello 单词的行
grep -v hello /etc/passwd 显示出在 /etc/passwd 文件里没有 hello 的行
grep -r hello /etc/ 在 /etc/ 目录里所有文件里找 hello 并显示结果
grep -i hello /etc/passwd --color=auto 在/etc/passwd 文件中找 hello 并且忽略大小写,然后高亮显示匹配的关键字
sed stream editor 对文本进行增删改查(过滤字符串 取出指定行)
sed的工作原理: 从文件中按行读取以后 加载到sed的模式空间 看是否符合pattern
不符合pattern则不输出到屏幕 符合pattern,处理然后输出屏幕
源文件单行--->sed模式空间--->pattern--->结果是否符合预期
sed格式:
sed [选项] [sed内置命令字符] [输入文件]
选项:
-n 通常与sed内置p结合使用 不匹配的不输出了
-i 修改的结果写入src文件, 如果不加-i修改的是sed本身的缓存
-e 多次编辑,不需要管道符了
-r 支持RE
sed内置命令:
a append在指定行后追加
d delete删除指定行
i insert在指定行插入一行或多行文本
p print查看指定行
s/pattern/替换内容/g 匹配pattern然后全局替换为想要替换的内容
sed的匹配范围:
空地址 全文处理
单地址 指定文件某一行
/pattern/ 符合pattern的每一行 /pattern1/, /pattern2/ 可以串联
范围区间 10,20 表示10到20行 10,+5 表示10到15行
指定搜索步长 1~2 表示从第1行开始 步长为2的行 如 1 3 5 7 9 2~2 表示从第2行开始,步长为2的行 如 2 4 6 8 10
# 测试文本 luffcity.txt
My name is change.
I teach Linux.
I Like play computer game.
My website is http://www.pythondoc.com.cn.
My sister is reading high school.
// sed查看
sed -n "2,4p" luffcity.txt ## 查看2-4行的文本
sed -n "2p" luffcity.txt ## 只查看第2行的文本
// sed查看 匹配/pattern/的行内容
sed -n "/linux/p" luffcity.txt
// sed 删除 包含game的行
sed -n "/game/d" luffcity.txt ## 只是删除了sed缓冲区的内容,并未对源文件进行修改
sed -n -i "/game/d" luffcity.txt ## 必须加 -i 如果想对源文件修改必须加该选项
sed -n -i "5,$d" luffcity.txt ## 把源文件从第5行开始到$(表示最后一行) d(sed内置命令) 全部删除
// sed 替换 模式
sed "s/你想找的内容/你想替换的内容/g" 全部替换 sed "s/pattern/替换内容/g"
sed "s#你想找的内容#你想替换的内容#g" 同上 (1)sed "s###" (2)sed "s@@@" (3) sed "s///"都可以
sed "s@你想找的内容@你想替换的内容@g" 同上
sed "行范围s/旧串/新串/g" 局部替换 按照行范围
// sed 替换源文件My 为 I
sed -i "s/My/I/g" luffcity.txt # -i 修改源文件 s///替换模式
// sed 多次编辑一个文件 把My换为I 把Linux替换Windows
sed -i -e "s/My/I/g" -e "/s/Linux/Windows/g" luffcity.txt
// sed 插入和追加 行
sed -i "2a This is new add line1" luffcity.txt ## 在第2行后追加(新行为第3行)
sed -i "4i This is new add line2" luffcity.txt ## 在第4行前追加(新行为第4行)
sed -i "2a Hello world\n Welcome here!" ## 在第2行追加2行
sed -i "2a\ This is new add line3" luffcity.txt ## 在第3行插入固定格式前有空格语句This is new add line3
// sed 空地址 表示全范围
sed -i "a --------" luffcity.txt ## 在sed内置命令a后空格 表示空地址 在每一行后面都添加分隔符 --------
awk作用: 模式扫描与文本处理语言
awk本身是一门语言,mawk是其awk的解释器;主要针对文本数据处理、检索等
awk的程序:【pattern{action}】序列对和【函数】构成。在命令行中输入短程序,通常用{ }括起来,以避免shell解释。
awk的数据类型: 数字、字符串
(1)awk [-F] "[分隔符]" '{print$1, $NF}' [目标文件]
(2)awk 'BEGIN {
FS="[列分隔符]+";
RS="[行分隔符]+";
print "-GEGIN-"} # begin部分
NR == n{动作} # NR部分
END {print "-END-"}' 目标文件 # End部分 【以上三部分都包裹在' '中】
----------------------------常用选项----------------------------------
-F 指定分隔符的值
-f 输入从文本文件中获取,而不是从命令行读取。允许多个-f选项
-v var=value为程序变量var赋值
----------------------------常用选项----------------------------------
----------------------------不常用选项----------------------------------
-W version mawk将其版本和版权写入stdout,并将编译限制写入stderr并退出0。 # 用法: awk -W version
-W dump 将程序内部表示的列表等汇编程序写入stdout,并退出0(成功编译时)。
-W交互式设置 对stdout的无缓冲写入和对stdin的行缓冲读取。来自stdin的记录是行,而不管RS的值如何。
-W执行文件 从文件读取程序文本,这是最后一个选项。在支持可执行脚本的#!“魔术数字”约定的系统上很有用。
-W sprintf=num 将mawk内部sprintf缓冲区的大小调整为num字节。此选项的使用非常罕见,表明应重新编译mawk。
-W posix_space 强制mawk不将'\n'视为空间。
短格式-W[vdisp]被识别,在某些系统上-我们必须避免命令行长度限制。
----------------------------不常用选项----------------------------------
主旋律: awk是写程序; 程序的结构是 pattern{action}序列对 以及 函数构成
pattern: (1) BEGIN (2) END (3) 表达式 其中之一
action: 比较灵活(变量赋值、语句集)
pattern{action}序列对: 两者必须存在一个; [BEGIN] {action} [END] 即省略pattern情况 隐式添加BEGIN END pattern[print] 即省略{action}隐式添加print
awk语句结束: \n 或 ;
空行语句: 也要以;结束
注释: #
在awk语言中,记录、字段、字符串通常被测试以匹配正则表达式
expr ~ /正则表达式/ # 是一个awk表达式,若匹配则返回1,不匹配返回0 expr ~// 匹配所有的空行
expr !~/正则表达式/ # 是一个awk表达式,若不匹配则返回1,匹配返回0 (取反上面的操作)
expr ~ /正则表达式/ <===> expr $0~/正则表达式/ # 两者是等价写法 (特殊情况:【匹配运算符】 或 【内置函数作为正则表达式参数】两者不等价)
示例: /^[_a-zA-Z][_a-zA-Z0-9]*$/ and # AWK标识符和AWK的数字常量匹配
/^[-+]?([0-9]+\.?|\.[0-9])[0-9]*([eE][-+]?[0-9]+)?$/ # 小数点的匹配必须经过转义
BEGIN { identifier = "[_a-zA-Z][_a-zA-Z0-9]*" } # 任何表达式都可以在~或!的右边使用!~运算符或传递给需要正则表达式的内置运算符
$0 ~ "^" identifier # 打印以标识符开头的所有行
记录: 一次读取一个记录,并存储在字段变量$0中; # $0表示整条记录
字段: 整条记录被划分成n个字段 # $1 、$2、$3 、......表示第一、二、三...个字段 (字段间以FS分割)
--------------------------------------内建变量--------------------------------------------
ARGC 命令行参数的ARGC数
ARGV 命令行参数的ARGV数组
ENVIRON 由环境变量索引的环境数组; 环境字符串,var=value存储为ENVIRON[var] = value;
FILENAME 当前输入文件的FILENAME名称
FNR FILENAME中的FNR当前记录编号(有多少行记录)
FS 拆分记录的分隔符 【列的分隔符】
NF 当前记录有多少个(number of fileds)字段 【字段】 $NF标识最后一列
NR 总输入流中的NR 【行号】
OFMT 用于打印号码的OFMT格式;初始=“%.6g”
OFS OFS会在输出的字段之间添加=,初始=“”
ORS ORS终止输出上的每个记录,最初=“\n”
RLENGTH 最后一次调用内置函数设置的RLENGTH长度,匹配()
RS RS输入记录分隔符,初始=“\n” 【行的分隔符】
RSTART 由最后一个调用设置的RSTART索引匹配()
SUBSEP 用于构建多个数组下标的SUBSEP,最初=“\034”
--------------------------------------内建变量--------------------------------------------
--------------------------------------内建函数--------------------------------------------
字符串处理函数:
(1) 全局替换函数 gsub(r,s,t) 或 gsub(r,s) # r被s替换
替换单条记录 sub(r,s,t) 或 sub(r,s)
(2) 查找子串索引 index(s,t) # s主串 t子串 s串的index从1开始计数 返回 0 失败 成功 返回对应位置
(3) 字符串长度 length(s)
(4) 字符串匹配 match(s, r)
(5) 拆分字符串 split(s, A, r) 或 split(s, A) # 拆分字符串s按照正则表达式r或者默认的分隔符拆分,将拆分后的字段存在A数组中
(6) 格式化字符串 sprintf(格式, 表达式)
(7) 截取字符串 substr(s, i, n) 或 substr(s, i); # i起始index n表示长度
(8) 字符串转化为大小写 tolower(s) 或 toupper(s)
数字处理函数:
(1) cos(x)、sin(x)
(2) exp(x) 指数函数
(3) int(x) 返回被截断为零的x
(4) log(x) 自然对数
(5) rand() 返回0 - 1 随机数
(6) sqrt(x) x的平方根
--------------------------------------内建函数--------------------------------------------
# -----------------------------------------------------------------------
#(1) 格式:从指定index截取固定长度
# ${string:start:length}
str_time="2022-02-01 14:36:58"
date_no=${str_time:0:10} # 截取前10个字符 2022-02-01
date_mon=${str_time:5:2} # 从第6位开始截取2位字符 02
date_time=${str_time:0-8} # 从后面截取8位字符 14:36:58
date_hh=${str_time:0-8:2} # 从后面第8位开始截取2个字符 14
echo "date_no = $date_no"
echo "date_mon = $date_mon"
echo "date_time = $date_time"
echo "date_hh = $date_hh"
teststr='/app/logs/133.38.112.177_202204111015.log'
#(2) 截取指定模式串左边的字符
# 格式1:${string%substr*}
# 格式2: ${string%%substr*}
echo "${teststr%11*}" # 打印 /app/logs/133.38.112.11_2022041
echo "${teststr%%11*}" # 打印 /app/logs/133.38.
#(3) 截取指定主串中模式串右边字符
# 格式1:${string#*substr} # # 从左向右第一个子串出现的位置
# 格式2:${string##*substr} # ##从左向右最后一个子串出现的位置
echo "${teststr#*11}" # 打印 2.11_202204111015.log
echo "${teststr##*11}" # 打印 015.log
主串#*子串: 删除第一个出现子串包括子串的前半段,保留主串的后半段
主串##*模式串: 删除最后一个出现子串包括子串的前半段,保留主串的后半段
主串%子串*: 删除最后一个出现的子串包括子串后边的字符,保留主串的前半段
主串%%*模式串: 删除从第一个出现子串包括子串后边的字符,保留主串的前半段
# -----------------------------------------------------------------------
# -----------------------------------------------------------------------
${str} 取字符串的值 等价于$str
${str-DEFAULT} 若str未被声明,那么就以DEFAULT作为其值 等价于 ${str=DEFAULT}
${str:-DEFAULT} 若str未被声明,或str的值为空,那么就以DEFAULT作为其值 等价于 ${str:=DEFAULT}
${str+OTHER} 若str已被声明,那么其值即设置为OTHER,否则就设置NULL字符串
${str:+OTHER} 若str已被声明,且值已被设定,修改其值为OTHER,否则就设置NULL字符串
${str?ERR_MSG} 检查str是否被被声明,若未声明则打印ERR_MSG
${str:?ERR_MSG}} 检查str是否已经被声明,且被设置,否则打印ERR_MSG
${!strPrefix*} 匹配之前所有的以strPrefix开头的变量
${!strPrefix@} 匹配之前所有的以strPrefix开头的变量
echo "${str-123}" # 对未声明的变量赋默认值 等价于 echo "${str=123}"
echo "${str:-456}" # 对未声明的变量、或未初始化的变量赋默认值 等价于 echo "${str:=456}"
var1=""
var2="000"
echo "${var1+333}" # 对已声明但未初始化的变量 设置特定值
echo "${var2:+333}" # 对已声明且已初始化的变量 修改为特定值
txt1=ab
txt2=cd
txt3=
echo ${!txt*} # 获取符合以txt开头子串的所有变量的变量名
输出结果:
123
456
333
333
txt1 txt2 txt3
# -----------------------------------------------------------------------
# -----------------------------------------------------------------------
${str:起始位置} 从起始位置截取到最后
${str:起始位置:长度} 从起始位置截取多长
${str#子串} 从str的【开头】删除最短的子串匹配
${str##子串} 从str的【开头】删除最长的子串匹配 ${str##*/} 获取文件名
${str%子串} 从str的【结尾】删除最短的子串匹配 ${str%/*} 获取目录
${str%%子串} 从str的【结尾】删除最长的子串匹配
${str/子串/替换的值} 使用替换的值来 代替 第一个子串 (精准匹配)
${str//子串/替换的值} 使用替换的值来 代替 所有子串 (精准匹配 替换所有匹配子串)
${str/#子串/替换的值} 如果str中前缀匹配到子串 就用替换的值(只能替换对应的开头)
${str/%子串/替换的值} 如果str中后缀匹配到子串 就用替换的值(只能替换对应的后缀)
原串:str=abc12342341
echo ${str#a*3} # 从头部开始 去除子串最短匹配格式 a*3 输出结果:42341
echo ${str#c*3} # 这样是什么都不会匹配到的 输出结果:abc12342341
echo ${str##a*3} # 41 从头部开始 去掉最长匹配的字符
echo ${str%3*1} # abc12342 从尾部开始,去掉最短匹配
echo ${str%%3*1} # abc12 从尾部开始,去掉最长匹配
echo ${str/23/bb} # abc1bb42341 从头开始 替换一次
echo ${str//23/bb} # abc1bb4bb41 从头开始 替换所有
echo ${str/#abc/bb} # bb12342341 #代表以什么开头来匹配
echo ${str/%abc/bb} # abc123423bb %代表以什么结尾来匹配
特例:
test='c:/windows/boot.init'
echo ${test//\//\\} # 主串//查找/替换值 //表示替换所有
# 查找值 需转义 "\/" (查找内容/)
# 替换 /
# 替换值 需转义 “\\” (替换内容\)
# -----------------------------------------------------------------------
5.4 字符串的长度、Index(默认起始index=1)、字符串的匹配
# -----------------------------------------------------------------------
${#str} 求字符串的长度 等价于 expr length $str
str="123.hello.json"
expr index $str '123' # 起始index = 1 结果:1
expr index $str "h" 结果:5
expr index $str "." # 第一个.出现的位置 结果:4
expr substr $str 3 3 # 截取字符串 从index = 3 截取三个字符
# 自定义显示匹配子串(两种格式)
(1)expr match $str '模式子串' # expr match $str '\([a-c]*[0-9]*\)' \(对圆括号转义 匹配内容
(2)expr $str : '模式子串' # expr $str '\([a-c]*[0-9]\)'
# -----------------------------------------------------------------------
(1) 比较
[[ "a.txt" == a* ]] # 逻辑真 pattern 匹配
[[ "a.txt" =~ .*\.txt ]] # 逻辑真 Regex 匹配
[[ "abc" == "abc" ]] # 逻辑真 string 比较
[[ "11" < "2" ]] # 逻辑真 按ASCII码值比较
(2) 连接
s1='hello'
s2='world'
echo ${s1}${s2} # helloworld 中间也可以加空格 echo ${s1} ${s2} 输出结果:hello world