一.sed 的高级用法
sed 中除了模式空间,还另外支持保持空间,利用此空间,可以将模式空间中的数据,临时保存至保持空间,从而后续接着处理,实现更为强大的功能。
常见命令:
选项 | 含义 |
P(大) | 打印模式空间开端至\n内容,并追加到默认输出之前 |
N | 读取匹配到的行的下一行追加至模式空间 |
n | 读取匹配到的行的下一行覆盖至模式空间 |
G | 从保持空间取出的内容追加至模式空间 |
g | 从保持空间取出的数据覆盖至模式空间 |
H | 把模式空间中的内容追加至保持空间 |
h | 把模式空间中的内容覆盖至保持空间 |
x | 把模式空间中的内容与保持空间中的内容进行互换 |
d | 删除模式空间中的行 |
D | 如果模式空间包含换行符,则删除直到第一个换行符的模式空间中的文本,并不会读取新的输入行,而使用合成的模式空间重新启动循环,如果模式空间不包含换行符,则会像发出d命令那样启动正常的新循环 |
操作:
原理:
打印偶数行的几个方法:
seq 10 | sed -n 'n;p'
seq 10 | sed -n '2~2p'
seq 10 | sed '1~2d'
seq 10 | sed -n '1~2!p'
二.awk
1.简介
AWK是一种优良的文本处理工具。它不仅是 Linux中也是任何环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一个人所拥有的知识。AWK 提供了极其强大的功能:可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上 AWK 的确拥有自己的语言:AWK 程序设计语言, 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
有多种版本:
-
AWK:原先来源于 AT & T 实验室的的AWK
-
NAWK:New awk,AT & T 实验室的AWK的升级版
-
GAWK:即GNU AWK。所有的GNU/Linux发布版都自带GAWK,它与AWK和NAWK完全兼容
2.awk
2.1 工作原理
前面提到 sed 命令常用于一整行的处理,而 awk 比较倾向于将一行分成多个"字段"然后再进行处理,且默认情况下字段的分隔符为空格或tab键,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。awk 执行结果可以通过 print 的功能将字段数据打印显示。
在使用awk命令的过程中,可以使用逻辑操作符"&&“表示"与”、"||“表示"或”、"!“表示"非”;还可以进行简单的数学运算,如+、-、*、/、%、^分别表示加、减、乘、除、取余和乘方。
awk 后面接两个单引号并加上大括号{ }来设置想要对数据进行的处理操作,awk 可以处理后续接的文件,也可以读取来自前个命令的标准输出。
2.2 命令的基本格式
awk [选项] '模式条件{操作}' 文件1 文件2...
注意:
① 一定是单引号: '模式或条件{操作}'
② {}外指定条件,{}内指定操作
③ 内建变量不能使用双引号括起来,不然系统会把它当成字符串
选项:
-v | 定义变量 |
-F | 指定分隔符 |
常见内置变量
内置变量 | 作用 |
NR | 当前处理的行的行号(序数) |
NF | 当前处理的行的字段个数 |
FS | 列分隔符,指定每行文本的字段分隔符,默认为空格或制表位。 与 “ -F ” 作用相同 |
OFS | 输出内容的列分隔符 |
RS | 行分隔符,awk从文件中读取资料时,将根据RS的定义把资料切割成许多条记录, 而awk一次仅读入一条记录进行处理。预设值是"\n" |
$0 | 当前处理的行的整行内容 |
$n | 当前处理行的第n个字段(第n列) |
FILENAME | 被处理的文件名 |
2.3 基本打印用法
2.3.1 打印文章所有内容
[root@localhost ~]#awk '{print}' /etc/passwd
注意:0 和 1 放置 {} 前,能够起到限制答应的作用(默认为“1”)
[root@localhost ~]#awk '{print $0}' /etc/passwd
2.3.2 打印行内容及其行号
[root@localhost ~]#awk '{print NR}' /etc/passwd
[root@localhost ~]#awk '{print NR,$0}' /etc/passwd
2.3.3 指定行和指定行范围打印
[root@localhost ~]#awk 'NR==3{print}' /etc/passwd
[root@localhost ~]#awk 'NR==3,NR==5{print}' /etc/passwd
[root@localhost ~]#awk 'NR>=3&&NR<=5{print}' /etc/passwd
2.3.4 奇偶行打印
[root@localhost ~]#awk 'NR%2==0{print}' /etc/passwd
#打印偶数行
[root@localhost ~]#awk 'NR%2==1{print}' /etc/passwd
#打印奇数行
2.3.5 奇偶打印特殊方式-- getline
getline工作过程:
(1)当getline左右无重定向符号(“<”)或者管道符号(“|”)时,awk首先读取的是第一行,而getline获取的是是光标跳转至下一行的内容(也就是第二行)
原因:getline运行之后awk会改变NF,NR,$0,FNR等内部变量,所以此时读取$0的行号不再为1,而是2
注意:
FNR:awk当前读取的记录数,其变量值小于等于NR,(比如说当读取完第一个文件后,读取第二个文件,FNR是会从0开始进行,而NR不会)。因此读取两个或两个以上的文件,NR==FNR,可以 判断是不是在读取第一个文件
(2)当getline左右有管道符号或重定向符时,getline则作用定向输入文件,由于文件是刚打开,并没有被awk读入一行,而只是getline读入,所以getline返回的是文件的第一行,而不是跳转至一行输入
打印偶数行
[root@localhost etc]#seq 10 |awk '{getline;print $0}'
打印奇数行
[root@localhost etc]#seq 10 |awk '{print $0;getline}'
2.3.6 文本内容匹配过滤打印
[root@localhost ~]#awk '/^root/{print}' /etc/passwd
[root@localhost ~]#awk '/bash$/{print}' /etc/passwd
2.4 BEGIN打印模式
2.4.1 BEGIN
格式:awk 'BEGIN{...};{...};END{...}' 文件
处理过程:
1、在 awk 处理指定的文本之前,需要先执行 BEGIN{...} 模式里的命令操作
2、中间的 {...} 是真正用于处理文件的命令操作
3、在 awk 处理完文件后才会执行 END{...}模式里的命令操作。END{ } 语句块中,往往会放入打印结果等语句。
awk是从c语言中继承到Linux,所以在BEGIN模式中变量x,可以直接运用,无需"$"声明获取变量值
[root@localhost etc]#awk 'BEGIN{x=0};{x++};END{print x}' /etc/passwd
2.4.2 BEGIN 计算
在 awk 处理指定的文本之前,需要先执行 BEGIN{...} 模式里的命令操作
2.5 对字段进行处理打印
2.5.1 指定分隔符打印字段
普通指定方式
[root@localhost etc]#awk -F ':' '{print$1}' /etc/passwd |head -n5
BEGIN模式指定
[root@localhost etc]#awk 'BEGIN{FS=":"};{print $1}' /etc/passwd |head -n5
2.5.2 条件判断打印
正向判断打印:
[root@localhost ~]#awk -F: '$3>=1000{print $3,$1}' /etc/passwd
#先用 -F指定分隔符为":" ,文件以":"分割的第三列为uid,uid大于1000的打印第三列和第一列,也就是uid和用户
判断取反打印:
[root@localhost ~]#awk -F: '!($3<=1000){print $3,$1}' /etc/passwd
还可以直接进行 if 语句判断打印:
[root@localhost ~]#awk -F: '{if($3>=1000){print $3,$1}}' /etc/passwd
2.5.3 提取 df 里面数字
[root@localhost ~]#df |awk '{print $5}'|tail -n +2 |tr -d %
或者
[root@localhost ~]#df |awk -F"[ %]+" '{print $5}'|tail -n +2
#[ %] 一个字符 看到空格和%,都当作分隔符 + 一个以上
[root@localhost ~]#df |awk -F"[[:space:]]+|%" '{print $5}'|tail -n +2
2.5.4 取ip地址
[root@localhost ~]#ifconfig ens33|awk '/netmask/{print $2}'
[root@localhost ~]#ifconfig ens33|sed -rn '2s/.*inet (.*) netmask.*/\1/p'
3.awk 的三元表达式与精准筛选
3.1 三元表达式
3.1.1 java和shell中的三元表达式
java中:
(条件表达式)?(A表达式或者值):(B表达式或者值)
解释:
条件表达式成立(为真)时,会取冒号前面的值A。 - 条件表达式不成立(为假)时,会取冒号后面的值B。
shell中:
[ 条件表达式 ] && A || B
解释:
条件表达式成立(为真)时,会取||前面的值A。 - 条件表达式不成立(为假)时,会取||后面的值B。
3.1.2 awk三元表达式的应用
格式:awk '(条件表达式)?(A表达式或者值):(B表达式或者值)'
[root@localhost ~]#awk -F: '{max=($3>=$4)?$3:$4;{print max,$0}}' /etc/passwd |sed -n '1,6p'
#比较passwd文件中第三列和第四列的大小
去他们结果较大的值,赋于变量max 并且输出max及其所在行的全部内容
3.2 awk 精准筛选
筛选方法:
$n (><==) | 用于对比数值 |
$n~"字符串" | 代表第n个字段,包含某个字符串的作用 |
$n!~"字符串" | 代表第n个字段,不好含某个字符串的作用 |
$n=="字符串" | 代表第n个字段为某个字符串的作用 |
$n!="字符串" | 代表第n个字段不为某个字符串的作用 |
$NF | 代表最后一个字段 |
操作:
① 输出第七个字段包含“bash”所在行的第一个字段和最后一个字段
[root@localhost ~]#awk -F: '$7~"bash"{print $1,$NF}' /etc/passwd
② 输出第七个字段不包含“nologin”所在行的第一个字段和最后一个字段
[root@localhost ~]#awk -F: '$7!~"nologin"{print $1,$NF}' /etc/passwd
③ 指定第六个字段为/home/xyl ,第七个字段为/bin/bash,输出满足这些条件的所在行
[root@localhost ~]#awk -F: '($6=="/home/xyl")&&($7=="/bin/bash"){print $0}' /etc/passwd
4.awk的分隔符
4.1 RS 指定分隔符
awk 从文件中读取资料时,将根据 RS 的定义把资料切割成许多条记录, 而 awk 一次仅读入一条记录进行处理。内置变量 RS 的预设值是"\n"。
但是也可以在使用 BEGIN 模式在操作前进行行分隔符的改变。
[root@localhost ~]#echo $PATH |awk 'BEGIN{RS=":"};{print NR,$0}'
4.2 指定输出的分隔符
4.2.1 FS 输入时的列分隔符
在里面定义:
在外面定义:
4.2.2 OFS 输出内容的列分隔符($n=$n 用于激活,否则不生效,n且必须存在)
[root@localhost ~]#echo A B C D |awk '{OFS="|";print $0;$1=$1;print $0}'
A B C D
A|B|C|D
[root@localhost ~]#awk -v FS=':' -v OFS='==' '{print $1,$3}' /etc/passwd
4.2.3 NF 代表字段的个数
[root@localhost ~]#awk -F: '{print $NF}' /etc/passwd
[root@localhost ~]#df | awk '{print $(NF-1)}'
$(NF-1) 倒数第二列
4.2.4 NR 显示行号
[root@localhost ~]#awk -F: '{print NR}' /etc/passwd
打印行号为2的
[root@localhost ~]#ifconfig ens33|awk 'NR==2'
[root@localhost ~]#ifconfig ens33|awk 'NR==2{print $0}'
[root@localhost ~]#ifconfig ens33|awk 'NR==2{print}'
2-5行
[root@localhost ~]#ifconfig ens33|awk 'NR>=2&&NR<=5{print}'
不要第1行
[root@localhost ~]#ifconfig ens33|awk 'NR!=1{print}'
4.2.5 FNR 分开显示行号
4.2.6 FILENAME 显示当前处理文件的名字
4.2.7 tr改变分隔符输出
格式:tr 原分隔符 改变后的分隔符
4.2.8 awk 改变输出分隔符
直接修改输出分隔符:
[root@localhost ~]#echo a b c d|awk '{OFS=":" ;$1=$1; print $0}'
BEGIN模式中修改输出分隔符:
[root@localhost ~]#echo a b c d|awk 'BEGIN{OFS=":"};{$1=$1; print $0}'
5.awk 结合数组运用
5.1 awk中定义数组打印
[root@localhost ~]#awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;print a[1]}'
20
[root@localhost ~]#awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;print a[0]}'
10
此外,awk中的数组还能形成遍历
[root@localhost ~]#awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;for(i in a)print i,a[i]}'
5.2 awk打印文件内容去重统计
5.2.1 去重打印数组
[root@localhost ~]#x=(10 10 10 20 30 20 30 20 40 10 30 10)
[root@localhost ~]#echo ${x[@]}|awk -v RS=' ' '!a[$1]++'
10
20
30
40
5.2.2 处理文件去重统计
原理:将文件的字段内容变为定义的数组下标,对其进行匹配读取累加(只有遇到完全一致的才会累加),此时重复的次数在for循环的作用下成为了数组对应下标的元素,所以输出该下标和元素(就等同于输出重复的字段内容 以及统计的重复次数)
6.关系表达式
关系表达式结果为“真”才会被处理
真:结果为非0值,非空字符串
假:结果为空字符串或0值
n=0 第一行为假,不打印
小编别:
奇偶数行
seq 5 |awk 'i=!i' 奇数行
#第1行 i=0 假=!假 真 打印
#第2行 i=1 真=!真 假 不打印
....
seq 5 |awk -v i=1 'i=!i' 偶数行
seq 5 |awk '!(i=!i)' 偶数行
7.awk脚本
8.小问题
8.1 提取下面的字段中的 IP地址和时间
法一:
[root@localhost data]#cat text.txt |sed -nr 's/(.*) - - \[(.*) \+.*/\1 \2/p'
法二:
[root@localhost data]#cat text.txt |awk -F"[[ ]" '{print $1,$5}'
[root@localhost data]#cat text.txt |awk -F"[[ ]+" '{print $1,$4}'
8.2 提取host.txt主机名再放回host.txt文件
[root@localhost data]#cat host.txt |awk -F"[ .]" '{print $2}' >> host.txt
[root@localhost data]#cat host.txt |cut -d "." -f1 |tr -d "[0-9 ]" >> host.txt
[root@localhost data]#cat host.txt |sed -nr 's/[0-9] (.*)\.kgc\.com/\1/p' >> host.txt
方法一:
方法二:
方法三:
8.3 统计 /etc/fstab 文件中每个文件系统类型出现的次数
[root@localhost data]#cat /etc/fstab |grep -v "^#"|grep -v "^$"|awk '{print $3}'|sort|uniq -c
8.4 统计单词个数
[root@localhost data]#cat /etc/fstab |grep -Eo "\b[[:alpha:]]+\b"|wc -l
8.5 提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的所有数字
8.6 查出/tmp/的权限,以数字方式显示
[root@localhost data]#stat /tmp|awk -F"[(/]" 'NR==4{print $2}'
8.7 查出用户UID最大值的用户名、UID及shell类型
[root@localhost data]#awk -F: '$3>=1000{print $3,$1}' /etc/passwd |sort -nr