正则表达式
- BRE:POSIX基础正则表达式
- ERE:POSIX扩展正则表达式
- BRE模式
- 行首 ^
- 行尾 $
- 点号字符:匹配除换行符之外的任意单个字符
- 字符组:中括号[1bdfhg]
- 排他型字符组:[^ab] 除ab字符外的任意字符
- 区间:[a-ch-m],a-c和h-m区间内的字符
- 特殊字符组
- [[:alpha:]] 任意字母字符,包含大小写
- [[:alnum:]] 0-9 A-Z a-z
- [[:blank:]] 空格和制表符
- [[:digit:]] 0-9
- [[:lower:]] a-z
- [[:upper:]] A-Z
- [[:print:]] 任意可打印字符
- [[:punct:]] 标点符号
- [[:space:]] 任意空白字符:空格 制表符 NL FF VT CR
- 星号:匹配模式出现0次到多次
- ERE模式
- 加号 + 至少出现一次
- 问号 ? 最多出现一次
- 花括号 {m}:出现m次 {m,n}:出现m到n次
- 管道符号:或 /cat|dog/
- 表达式分组:小括号,当使用此模式时,改组会被视为一个标准字符
cut
- 选项
- b 按字节分割
- c 按字符分割
- d 指定分割符
- f 指定字段,与d搭配
- n 不要分割多字符
who | cut -b 1-10,20-
# 返回:分割的1和3列
cut -d : -f 1,3 /etc/passwd
echo "我这一下下你怕是要嘤嘤嘤"|cut -c 3-5 # 一下下
# 乱码
echo "我这一下下你怕是要嘤嘤嘤"|cut -b 3-5
echo "我这一下下你怕是要嘤嘤嘤"|cut -n -b 3-5 # 一下下
awk gawk
- 使用
BEGIN{...}
{...}
END{...}
- 用途
- 定义变量来保存数据
- 使用算术和字符串操作符来处理数据
- 使用结构化编程概念(if-then等)来为数据增加处理逻辑
- 通过提取数据文件中的数据元素,将其重新格式化或排列,生成格式化报告
- awk options program file
- 选项
- F 指定分割符
- f file 从指定文件读取程序
- 内建变量
- FIELDWIDTHS 由空格分割的一串数字,定义了每个数据字段确切宽度
- FS 输入字段分割符
- RS 输入记录分割符
- OFS 输出字段分割符
- ORS 输出记录分割符
- ARGC 命令行参数,awk脚本不算参数
- ARGV 参数数组
- ARGIND 当前文件在ARGV的位置
- FNR 当前数据文件中已处理的输入记录数
- NR 已处理的输入记录数
- NF 数据文件的字段总数
- 自定义变量
#script.awk
BEGIN{print "The starting value is",n; FS=","}
{print $n}
# 自定义变量使用-v来指定,这样BEGIN里变量才生效。如果使用 awk -f script.awk n=3 data1,则n变量在BEGIN不生效
awk -v n=3 -f script.awk data1
- 处理数组
BEGIN{
# 定义数组变量
city["bj"]="BeiJing"
city["sh"]="ShangHai"
city["cq"]="ChongQing"
# 遍历
for(var in city){
print "index:",var," - value:",city[var]
}
# 删除
delete city["bj"]
for(var in city){
print "index:",var," - value:",city[var]
}
}
- 使用模式,匹配操作符(~)
# 找到匹配模式 111 的行,打印第一列数据
awk '/111/{print $1}' data.txt
# 第一列数据匹配模式/111/的打印整行
awk '$1 ~ /111/{print $0}' data.txt
# 第一列数据不匹配模式/111/的打印整行
awk '$1 !~ /111/{print $0}' data.txt
# 使用表达式,可使用的符号有==,<=,<,>=,>
awk '$4==0{print $1}' /etc/passwd
- 结构化命令
# if( condition ){ statement } else { statement }
awk '{if($1>20) {print $1}}' data.txt
# while( condition ){ statement }
echo -e "1 2 3\n4 5 6\n7 8 9"|awk '{
total = 0
i = 1
while( i<4 ){
total += $i
i++
}
avg = total / 3
print "Average:",avg
}'
# do{ statement } while( condition )
# for(i=1;i<100;i++){statement}
- 格式化打印:printf ,%[修饰字符]控制字符
- 控制字符
- c 字符
- d(i) 数字
- e 科学计数法
- f 浮点数
- g 科学计数或浮点数显示(自动选择较短的格式)
- o 八进制
- s 字符串
- x 十六进制 %#x
- X 十六进制,但是使用大写的A~F, %#X
- 修饰字符,[± #0][width].[prec]
- width:指定了输出字段的最小宽度的数字值。如果输出短于这个值,printf会将文本右对齐,并用空格进行填充。如果输出的长度大于指定宽度字符,则按实际输出
- prec:这是一个数字值,指定了浮点数中小数点后面的位数,或者文本字符串中显示的最大字符数
- -(减号)左对齐
- 控制字符
# 左对齐输出16进制数 带0X前缀
%#-10X
%10.2f
# 格式化输出
awk -F: '{printf "%-20s %s\n",$1,$7}' /etc/passwd
- 内建函数
- 数学函数
- cos(x) sin(x)
- log(x) x的自然对数
- sqrt(x) x的平方根
- exp(x) x的指数函数 e^x
- int(x) x的取整
- rand() 返回0-1之间的浮点数
- srand(x) 为计算随机数指定一个种子值
- and(v1,v2) 按位与运算
- compl(v1) 补运算
- lshift(v1,count) 向左移count位
- or(v1,v2) 按位或
- xor(v1,v2) 按位异或
- rshift(v1,count)
- 字符串函数
- asort(s[,d]):将数组s按数据元素排序。索引值会被替换为新的排序顺序的连续数字,另外,如果指定了d,则排序后数组会存储在数组d中
- asorti(s[,d]):将数组s按索引值排序。生成的数组会将索引值作为数据元素值,用连续数字索引来表明排序顺序,另外,如果指定了d,则排序后数组会存储在数组d中
- gensub(r, s, h [,t]) 查找变量$0或字符串t来匹配正则表达式r。如果h是一个以g或G开头的字符串,就用s替换掉匹配的文本。如果h是一个数字,它表示要替换掉第h处匹配r的地方。返回值为替换后的文本,$0变量不会改变
- gsub(r, s [,t]) 查找变量$0或字符串t来匹配正则表达式r。如果找到了,就用s替换掉匹配的文本。返回替换的次数,$0会被替换
- index(s, t) 返回字符串t在字符串s中的索引值,如果没找到返回0,索引值从1开始
- length([t]) 返回字符串t的长度,如果没有指定,则返回$0的长度
- match(s, r [,a]) 返回字符串s中正则表达式r出现位置的索引,如果指定了数组a,它会存储s中匹配正则表达式的那部分
- split(s, a [,r]) 将s用FS字符或正则表达式r(如果指定)分开到数组a中,返回字段的总数
- sprintf(format,variables) 返回一个printf格式字符串
- sub(r, s [,t]) 在变量$0或目标字符串t中查找正则表达式r的匹配。如果找到了,就用字符串s替换掉第一处匹配
- substr(s, i [,n]) 截取字符串[i:n]
- tolower(s) 小写转换
- touppeer(s) 大写转换
- 时间函数
- mktime(datespec) 将YYYY MM DD HH MM SS[DST]格式指定日期转换为时间戳值
- strftime(format [,timestamp]), 采用shell date()函数的格式,不提供采用当前时间戳
- systime() 返回当前系统时间戳
- 数学函数
awk -F: '{ $0=gensub("root","replace_root","g");print $0}' /etc/passwd|head -5
awk -F: '{ gsub("root","replace_root");print $0}' /etc/passwd|head -5
awk 'BEGIN{ print index("junmocsq","csq")}' # 6
- 自定义函数,需要出现的所有块之前,包含BEGIN块 function myfunc([variables]){ statements }
sed
-
sed options function file
-
处理数据流程
- 一次从输入读取一行数据
- 根据所提供的编辑器命令匹配数据
- 按照命令修改流中的数据
- 将新的数据输出到STDOUT
-
选项
- n 安静模式,只有经过处理的行才会被列出来,默认sed是展示所有行的
- e 直接在命名行编辑,执行多个命令时用分号隔开。sed -e ‘s/root/jroot/g; s/bin/jbin/g’ passwd
- f 直接将sed操作写在文件里,-f filename直接执行filename里的sed操作
- r 扩展型正则语法
- i 直接修改读取的文件内容
-
function
a 新增
:在指定的行数下一行添加指定字符串(下一行)
[work@VM-16-2-centos ~]$ head -5 passwd |nl|sed '1,3ajunmo' 1 root:x:0:0:root:/root:/bin/bash junmo 2 bin:x:1:1:bin:/bin:/sbin/nologin junmo 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin junmo 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
c 替换
:替换行数为指定字符串
[work@VM-16-2-centos ~]$ head -5 passwd |nl|sed '1,3c\' 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin [work@VM-16-2-centos ~]$ head -5 passwd |nl|sed '1,3cjunmo' junmo 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
d 删除
:删除指定行数
$ head -5 passwd |nl|sed '1,3d' 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin # 删除模式/1/ 和 模式/3/ 区间之内的行 $ sed '/1/,/3/d' test.txt
i 插入
:在指定的行数上一行添加指定字符串(上一行)
[work@VM-16-2-centos ~]$ head -5 passwd |nl|sed '1,3ijunmo' junmo 1 root:x:0:0:root:/root:/bin/bash junmo 2 bin:x:1:1:bin:/bin:/sbin/nologin junmo 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
p 打印
= 打印行号
l (小写L)列出不可打印的ASCII字符
$ head -5 passwd|sed -n '=;l;y/123/789/' 1 root:x:0:0:root:/root:/bin/bash$ 2 bin:x:1:1:bin:/bin:/sbin/nologin$ 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin$ 4 adm:x:3:4:adm:/var/adm:/sbin/nologin$ 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin$
s 替换
:采用正则替换
[work@VM-16-2-centos ~]$ head -5 passwd |nl|sed '1,3s/bin/junmo/g' 1 root:x:0:0:root:/root:/junmo/bash 2 junmo:x:1:1:junmo:/junmo:/sjunmo/nologin 3 daemon:x:2:2:daemon:/sjunmo:/sjunmo/nologin 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
c 修改整行
:
# 匹配到adm的行替换为 字符串test abc $ head -5 passwd |nl |sed '/adm/c test abc' 1 root:x:0:0:root:/root:/junmo/bash 2 junmo:x:1:1:junmo:/junmo:/sjunmo/nologin 3 daemon:x:2:2:daemon:/sjunmo:/sjunmo/nologin test abc 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
y 转换命令
:处理单个字符
# 把1 2 3 分别替换为4 5 6 $ sed 'y/123/789/' passwd root:x:0:0:root:/root:/bin/bash bin:x:7:7:bin:/bin:/sbin/nologin daemon:x:8:8:daemon:/sbin:/sbin/nologin adm:x:9:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
w 写入文件
:[address]w filenamer 从文件读取数据
:[address]r filename,从文件读取数据,添加到address之后。address只支持单个行号或文本模式地址
sed '1,3w passwd.test' passwd sed '1r /etc/passwd' passwd
-
原地编辑内容保存
[work@VM-16-2-centos ~]$ head -3 passwd
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
# 1-2行替换bin,并修改文件
[work@VM-16-2-centos ~]$ sed -i '1,2s/bin/--zl--/g' passwd
[work@VM-16-2-centos ~]$ head -3 passwd
1 root:x:0:0:root:/root:/--zl--/bash
2 --zl--:x:1:1:--zl--:/--zl--:/s--zl--/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
[work@VM-16-2-centos ~]$
- 新增多行 用\分开
[work@VM-16-2-centos ~]$ head -5 passwd|sed -e '1,3a junmo\
csq\
kk'
1 root:x:0:0:root:/root:/bin/bash
junmo
csq
kk
2 bin:x:1:1:bin:/bin:/sbin/nologin
junmo
csq
kk
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
junmo
csq
kk
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[work@VM-16-2-centos ~]$
- 正则替换
[work@VM-16-2-centos ~]$ ifconfig eth0|grep 'inet '
inet 172.17.16.2 netmask 255.255.240.0 broadcast 172.17.31.255
[work@VM-16-2-centos ~]$ ifconfig eth0|grep 'inet '|sed -r 's/.*inet +//g'
172.17.16.2 netmask 255.255.240.0 broadcast 172.17.31.255
[work@VM-16-2-centos ~]$ ifconfig eth0|grep 'inet '|sed -r 's/.*inet +//g'|sed -r 's/ +netmask.*//g'
172.17.16.2
sed高级用法
- 多行命令
- N:将数据流中的下一行加进来创建一个多行组来处理
- D:删除多行组中的一行
- P:打印多行组中的一行
# 合并两个行:sed命令会查找单词first的那行,找到之后,它会将下一行和并到那行,然后用替换命令s将换行符替换成空格
sed '/first/{N ; s/\n/ /}' data.txt
- 模式空间(pattern space):是一块活跃的缓冲区,在sed编辑器执行命令时它会保存检查的文本。
- n 将模式空间文本移动到下一行
- 保持空间(hold space):sed编辑器在处理某些行的时候。可以用来临时保存一些行
- h 将模式空间复制到保持空间
- H 将模式空间附加到保持空间
- g 将保持空间复制到模式空间
- G 将保持空间附加到模式空间
- x 交换模式空间和保持空间的内容
- 排除命令:感叹号
# 除了header那一行,其他的都打印出来
sed -n '/header/!p' data.txt
- 反转文本(tac也可以):sed -n ‘{1!G; h ; $p}’ data.txt
- 1.在模式空间中放置一行
- 2.将模式空间中的行放到保持空间中
- 3.在模式空间中放入下一行
- 4.将保持空间附加到模式空间后
- 5.将模式空间中的所有内容都放到保持空间
- 6.重复执行3-5步,直到所有行都反序到了保持空间
- 7.提取并打印行
- 改变流
- 分支branch:[address]b [label],根据地址跳转到标签
# 第2,3行跳过后两个替换命令 sed '{2,3b ; s/test/TEST/; s/abc/ABC/}' data.txt # 匹配到first的行跳转到第二个替换命令,没有匹配的使用第一个替换命令 sed '{/first/ b jump1; s/test/no jump/; :jump1 s/test/jump/}' data.txt # 下面两个脚本都是循环替换逗号,但是第一个脚本有问题,会一直查找逗号,直到CTRL+C发送信号停止 echo "This , is , a, test, to, remove, commas."|sed -n '{:start;s/,//1p;b start}' echo "This , is , a, test, to, remove, commas."|sed -n '{:start;s/,//1p;/,/b start}'
- 测试test:[address]t [label],如果成功匹配并替换一个模式,测试命令就会跳转到指定的标签
# 第一个匹配模式不成功则使用第二个模式匹配 sed '{s/first/matched/ ;t ; s/This is the/No match on/}' data.txt # 模式匹配成功则继续循环执行 echo "This , is , a, test, to, remove, commas."|sed -n '{:start ;s/,//1p;t start}'
- 模式替代
- &符号:代表替换命令中匹配的模式
- 替代单独的单词:子模式,\1 \2 代替第一 第二个子模式,
# the "cat" sleeps in his "hat". echo "the cat sleeps in his hat."|sed 's/.at/"&"/g' # That cat is pretty echo "That furry cat is pretty"|sed 's/furry \(.at\)/\1/' # 大数字之间插入逗号 1,234,567,890 echo "1234567890"|sed '{:start; s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/; t start}'
- 使用例子
# 加倍行间距,每一行将保持空间附加到模式空间
sed 'G' data.txt
# 加倍行间距,尾行不加倍
sed '$!G' data.txt
# 对可能含有空白行的文件加倍行间距
sed '/^$/d; $!G' data.txt
# 给文件加行编号nl和cat -n也有此功能
sed '=' data1.txt|sed 'N;s/\n/ /'
# 打印最后10行文件,$q如果文件为尾行,退出;N 否则,把下一行加入模式空间;11,$D,如果当前行在10行之后,则删除模式空间第一行
sed '{:start ; $q; N; 11,$D; b start}' data.txt
tail -10 data.txt
# 删除连续的空白行,当存在数据的一行和空白行连续时不删除,多余的空白行则删除
sed '/./,/^$/!d' data.txt
# 删除开头的空白行
sed '/./,$!d' data.txt
# 删除结尾的空白行
sed '{:start; /^\n*$/{$d ; N ; b start}}' data.txt
# 删除html标签
sed 's/<[^>]*>//g; /^$/d' data.txt