shell三剑客(sed+awk)
Posted 郭怀远
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell三剑客(sed+awk)相关的知识,希望对你有一定的参考价值。
文章目录
一、sed
1. sed的工作流程
- 首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上
- sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会修改原文件
- sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等
2. sed的使用
sed常见的语法格式有两种,一种叫命令模式,另外一种叫脚本模式
1)命令模式
语法格式
sed [选项] 'sed的命令|地址定位' filename
注意:引用shell script中的变量应使用双引号,而非通常使用的单引号
常用选项:
-e 进行多项编辑,即对输入行应用多条sed命令时使用
-n 取消默认的输出
-f 指定sed脚本的文件名
-r 使用扩展正则表达式
-i 原地编辑(修改源文件)
创建test.txt文件
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
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
298374837483
172.16.0.254
10.1.1.1
常用命令和选项
p
:打印行d
:删除行
[root@localhost ~]# sed 'p' test.txt
# 打印全部,并取消默认输出
[root@localhost ~]# sed -n 'p' test.txt
# 打印第一行
[root@localhost ~]# sed -n '1p' test.txt
# 打印第二行
[root@localhost ~]# sed -n '2p' test.txt
# 打印1到5行
[root@localhost ~]# sed -n '1,5p' test.txt
# 打印5到8行
[root@localhost ~]# sed -n '5,8p' test.txt
# 打印最后一行
[root@localhost ~]# sed -n '$p' test.txt
# 打印所有行,且第5行打印2两遍
[root@localhost ~]# sed '5p' test.txt
# 只打印第5行
[root@localhost ~]# sed -n '5p' test.txt
# 删除第一行,并且打印默认输出
[root@localhost ~]# sed -n '1d' test.txt
# 不打印默认输出,删除第一行
[root@localhost ~]# sed -n '1d' test.txt
# 删除1到5行
[root@localhost ~]# sed '1,5d' test.txt
# 删除最后一行
[root@localhost ~]# sed '$d' test.txt
i\\
:在当前行之前插入文本。多行时除最后一行外,每行末尾需用""续行 vim——>Oa\\
:在当前行后添加一行或多行。多行时除最后一行外,每行末尾需用“\\”续行 vim——> oc\\
:用此符号后的新文本替换当前行中的文本。多行时除最后一行外,每行末尾需用""续行 整行替换
# 在最后一行插入 hello
[root@localhost ~]# sed '$ahello' test.txt
# 在每一行下面都插入 hello
[root@localhost ~]# sed 'ahello' test.txt
# 在第5行下面插入 hello world
[root@localhost ~]# sed '5ahello world' test.txt
# 在1到5行下面插入 hello world
[root@localhost ~]# sed '1,5ahello world' test.txt
# 在每一行上面都插入
[root@localhost ~]# sed 'i\\
> 111aaa\\
> 222bbb\\
> 333333' test.txt
# 在最后一行后面插入
[root@localhost ~]# sed '$a\\
> ababa\\
> 666' test.txt
sed匹配正则
如果sed要匹配正则,就要用/表达式/
包住
# 把包含root 的行替换成 hahaha
[root@localhost ~]# sed '/root/chahaha' test.txt
# 把以数字 1开头的行替换成 hello
[root@localhost ~]# sed '/^1/chello' test.txt
# 把以 n 结尾的行替换成 hello
[root@localhost ~]# sed '/n$/chello' test.txt
# 把包含小写字母的行替换成 666
[root@localhost ~]# sed '/[a-z]/c666' test.txt
#把第3行替换成 hello world
[root@localhost ~]# sed '3chello world' test.txt
r
:从文件中读取w
:将所选的行写入文件
# 读取 /etc/hosts 的内容插入到 tmp.txt 第3行下面
[root@localhost ~]# sed '3r /etc/hosts' tmp.txt
# 读取 /etc/hosts 的内容插入到 tmp.txt 最后一行下面
[root@localhost ~]# sed '$r /etc/hosts' tmp.txt
正则匹配
# 把 tmp.txt文件中包含 root的行写入到 test.txt文件中
[root@localhost ~]# sed '/root/w test.txt' tmp.txt
# 把 tmp.txt 文件中包含小写字母的行写入到 test.txt 文件中
[root@localhost ~]# sed '/[a-z]/w test.txt' tmp.txt
# 把tmp.txt 文件中包含连续4个数字的行写入到test.txt文件中
root@localhost ~]# sed -r '/[0-9]4/w test.txt' tmp.txt
# 把 tmp.txt文件里的ip地址写入到 test.txt 文件中
[root@localhost ~]# sed -r '/([0-9]1,3\\.)3[0-9]1,3/w test.txt' tmp.txt
!
:对所选行以外的所有行应用命令,放到行数之后
# 打印除了第一行的所有行
[root@localhost ~]# sed -n '1!p' tmp.txt
# 打印第4行
[root@localhost ~]# sed -n '4p' tmp.txt
#打印除了第四行的所有行
[root@localhost ~]# sed -n '4!p' tmp.txt
# 打印1到4行
[root@localhost ~]# sed -n '1,4p' tmp.txt
# 除了1到4行都打印
[root@localhost ~]# sed -n '1,4p' tmp.txt
s
:用一个字符串替换另一个g
:在行内进行全局替换
注意:搜索替换中的分隔符可以自己指定
# 把小写root替换成大写ROOT 值替换一个
[root@localhost ~]# sed -n 's/root/ROOT/p' tmp.txt
# 把小写root替换成大写ROOT,全部替换
[root@localhost ~]# sed -n 's/root/ROOT/gp' tmp.txt
# 如果开头是2就把2删除
[root@localhost ~]# sed -n 's/^2//gp' tmp.txt
# 把/sbin/nologin 替换成 hello
[root@localhost ~]# sed 's@/sbin/nologin@hello@gp' tmp.txt
# 注释掉前5行
[root@localhost ~]# sed -n '1,5s@^@#@gp' tmp.txt
&
:保存查找串以便在替换串中引用(或者\\(\\)
)
# & 等价于 #
[root@localhost ~]# sed -n 's/root/#&/p' tmp.txt
# 注释掉以root开头的行
[root@localhost ~]# sed -n 's/^root/#&/p' /etc/passwd
# 注释掉以root开头或者以bin开头的行
[root@localhost ~]# sed -n -r 's/^root|^bin/#&/p' /etc/passwd
# 注释掉1~5行中以任意小写字母开头的行
[root@localhost ~]# sed 's/^[a-z]/#&/gp' /etc/passwd
# 注释1~5行
[root@localhost ~]# sed -n '1,5s/^/#/gp' /etc/passwd
# 以#开头的替换成空
sed -n '1,5s/^#//p' passwd
# \\1 等价于 root
[root@localhost ~]# sed -n 's/\\(root\\)/\\1 test/gp' tmp.txt
=
:打印行号
# 打印以bash结尾的行的行号
[root@localhost ~]# sed -n '/bash$/=' passwd
# 执行多条命令,包含root的行号打印那行
[root@localhost ~]# sed -ne '/root/=' -ne '/root/p' /etc/passwd
[root@localhost ~]# sed -n '/nologin$/=;/nologin$/p' tmp.txt
[root@localhost ~]# sed -ne '/nologin$/=' -ne '/nologin$/p' tmp.txt
综合运用
注释一到5行
[root@localhost ~]# sed -n '1,5s/^/#/p' tmp.txt
[root@localhost ~]# sed -n '1,5s/\\(^\\)/#\\1/p' tmp.txt
常用选项
-e
:多项编辑-r
:使用扩展正则-i
:修改源文件
# 打印以root开头的行,并打印行号
[root@localhost ~]# sed -ne '/root/p' tmp.txt -ne '/root/='
# 在tmp.txt文件的第5行前面插入hello world,在第6行下面插入 你好世界
[root@localhost ~]# sed -e '5ihello world' -e '6a你好世界' tmp.txt -e '5=;8='
# 过滤vsftpd.conf文件中以#开头和空行
[root@localhost ~]# sed -e '/^#/d' -e '/^$/d' /etc/vsftpd/vsftpd.conf
[root@localhost ~]# sed '/^#/d;/^$/d' /etc/vsftpd/vsftpd.conf
[root@localhost ~]# sed -r '/^#|^$/d' /etc/vsftpd/vsftpd.conf
[root@localhost ~]# grep -Ev '^#|^$' /etc/vsftpd/vsftpd.conf
# 过滤smb.conf文件中生效的行
[root@localhost ~]# sed '/^#/d;/^$/d;s/\\t//' /etc/samba/smb.conf
# 过滤出tmp.txt文件中的IP地址
[root@localhost ~]# sed -nr '/([0-9]1,3\\.)3[0-9]1,3/p' tmp.txt
[root@localhost ~]# grep -E '([0-9]1,3\\.)3[0-9]1,3' tmp.txt
# 过滤出ifcfg-ens33 文件中的IP、子网掩码、广播地址
[root@localhost ~]# sed -nr '/([0-9]1,3\\.)3[0-9]1,3/p' /etc/sysconfig/network-scripts/ifcfg-ens33 | cut -d '=' -f2
[root@localhost ~]# sed -nr '/([0-9]1,3\\.)3[0-9]1,3/p' /etc/sysconfig/network-scripts/ifcfg-ens33 | sed -n 's/[A-Z=]//gp'
[root@localhost ~]# grep -Eo '([0-9]1,3\\.)3[0-9]1,3' /etc/sysconfig/network-scripts/ifcfg-ens33
# -i 选项 直接修改原文件
[root@localhost ~]# sed -i 's/root/ROOT/;s/bin/BIN/' tmp.txt
注释前5行
[root@localhost ~]# sed -i '1,5s/^/#/' tmp.txt
注意:
-ni 不要一起使用
p命令 不要再使用-i时使用
- 其它命令
y命令
该命令与UNIX/Linux中的tr命令类似,字符按照一对一的方式从左到右进行转换。
正则表达式元字符对y命令不起作用。与s命令的分隔符一样,斜线可以被替换成其它的字符。
s/xxx/xxx/
y/xxx/xxx/
注意源字符和替换字符数量要一致
# sed '39,41y/stu/STU/' /etc/passwd
# sed '39,41y/stu:x/STU@%/' /etc/passwd
q 退出
# sed '5q' 1.txt
# sed '/mail/q' 1.txt
# sed -r '/^yunwei|^mail/q' 1.txt
[root@server ~]# sed -n '/bash$/p;10q' 1.txt
ROOT:x:0:0:root:/root:/bin/bash
2)脚本格式
基本语法
执行脚本:# sed -f 文件名
或者:./sed.sh 文件名
脚本第一行
#!/bin/sed -f
注意事项
1) 脚本文件是一个sed的命令行清单。'commands'
2) 在每行的末尾不能有任何空格、制表符(tab)或其它文本。
3) 如果在一行中有多个命令,应该用分号分隔。
4) 不需要且不可用引号保护命令
5) #号开头的行为注释
示例
#!/bin/sed -f
s/root/hello/g
5a测试
#!/bin/sed -f
2a\\
******************
2,$s/stu/user/
$a\\
we inster new line
s/^[a-z].*/#&/
#!/bin/sed -f
3a**********************
$chelloworld
1,3s/^/#&/
3. 总结
1、正则表达式必须以”/“前后规范间隔
例如:sed '/root/d' file
例如:sed '/^root/d' file
2、如果匹配的是扩展正则表达式,需要使用-r选来扩展sed
grep -E
sed -r
+ ? () n,m | \\d
注意:
在正则表达式中如果出现特殊字符(^$.*/[]),需要以前导 "\\" 号做转义
eg:sed '/\\$foo/p' file
3、逗号分隔符
例如:sed '5,7d' file 删除5到7行
例如:sed '/root/,/ftp/d' file
删除第一个匹配字符串"root"到第一个匹配字符串"ftp"的所有行本行不找 循环执行
4、组合方式
例如:sed '1,/foo/d' file 删除第一行到第一个匹配字符串"foo"的所有行
例如:sed '/foo/,+4d' file 删除从匹配字符串”foo“开始到其后四行为止的行
例如:sed '/foo/,~3d' file 删除从匹配字符串”foo“开始删除到3的倍数行(文件中)
例如:sed '1~5d' file 从第一行开始删每五行删除一行
例如:sed -nr '/foo|bar/p' file 显示配置字符串"foo"或"bar"的行
例如:sed -n '/foo/,/bar/p' file 显示匹配从foo到bar的行
例如:sed '1~2d' file 删除奇数行
例如:sed '0-2d' file 删除偶数行 sed '1~2!d' file
5、特殊情况
例如:sed '$d' file 删除最后一行
例如:sed '1d' file 删除第一行
6、其他:
sed 's/.//' a.txt 删除每一行中的第一个字符
sed 's/.//2' a.txt 删除每一行中的第二个字符
sed 's/.//N' a.txt 从文件中第N行开始,删除每行中第N个字符(N>2)
sed 's/.$//' a.txt 删除每一行中的最后一个字符
二、awk
1. awk概念
-
awk是一种编程语言,主要用于在linux/unix下对文本和数据进行处理,是linux/unix下的一个工具。数据可以来自标准输入、一个或多个文件,或其它命令的输出。
-
awk的处理文本和数据的方式:逐行扫描文件,默认从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。
-
awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。
-
gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。
-
下面介绍的awk是以GNU的gawk为例的,在linux系统中已把awk链接到gawk,所以下面全部以awk进行介绍
2. awk使用
1)命令模式语法
awk 选项 '表达式' 文件名
常用选项
-F
:定义字段分割符号,默认的分隔符是空格-v
:定义变量并赋值
命名部分
正则表达式,地址定位
'/root/awk语句' 在sed中:'/root/p'
'NR==1,NR==5awk语句' 在sed中:'1,5p'
'^root/,/^ftp/awk语句/' 在sed中:‘/^root/,/^ftp/p’
awk语句1;awk语句2;…
'print $0;print $1' sed中:'p'
'NR==5print $0' sed中:'5p'
注意:awk命令语句间用分号隔开
BEGIN…END…
'BEGINawk语句;处理中;ENDawk语句'
'BEGINawk语句;处理中'
'处理中;ENDawk语句'
注意:如果要引用shell变量需要用双引号括起来
2)脚本模式
脚本执行方式
方法1
awk 选项 -f awk的脚本文件 要处理的文件
awk -f awk.sh filename
sed -f sed.sh -i filename
方法2
./awk的脚本文件(或者绝对路径) 要处理的文本文件
./awk.sh filename
./sed.sh filename
脚本编写
#!/bin/awk -f 定义魔法字符
以下是awk引号里的命令清单,不要用引号保护命令,多个命令用分号间隔
BEGINFS=":"
NR==1,NR==3print $1"\\t"$NF
...
3. awk内部相关变量
1)变量使用示例
变量 | 变量说明 | 备注 |
---|---|---|
$0 | 当前处理行的所有记录 | |
$1,$2,$3…$n | 文件中每行以间隔符号分割的不同字段 | awk -F: ‘print $1,$3’(以:分割截取第一列和第3列) |
NF | 当前记录的字段数(列数) | awk -F: ‘print NF’(以冒号分割后一行有多少列) |
$NF | 最后一列 | $(NF-1)表示倒数第二列 |
FNR/NR | 行号 | |
FS | 定义间隔符 | ‘BEGINFS=“/”;print $1,$3’(以/作为分割符号) |
OFS | 输出记录分割符,默认换行 | ‘BEGINFS=“:”;OFS=“@@”;print $1,$3’ |
RS | 输入记录分割符,默认换行 | ‘BEGINRS=“/”;print $0’ |
ORS | 输出记录分割符,默认换行 | ‘BEGINORS=“\\n@”;print $1,$3’ |
FILENAME | 当前输入的文件名 |
创建 test.txt文件
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
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
示例1
# 以冒号分割截取第一列和倒数第二列
[root@localhost ~]# awk -F: 'print $1,$(NF-1)' test.txt
# 以冒号分割截取第一行和倒数第二行和最后一列,统计字段数
[root@localhost ~]# awk -F: 'print $1,$(NF-1),$NF,NF' test.txt
# 打印包含root的行
[root@localhost ~]# awk '/root/print $0' test.txt
[root@localhost ~]# awk '/root/' test.txt
# 分割最后1列和第一列
[root@localhost ~]# awk -F: '/root/print $1,$NF' test.txt
# 打印处理的行
[root@localhost ~]# awk -F: '/root/print $0' test.txt
# 打印第1行到第5行
[root@localhost ~]# awk 'NR==1,NR==5' test.txt
[root@localhost ~]# awk 'NR==1,NR==5print $0' test.txt
# 打印1到5行,和以root开头
[root@localhost ~]# awk 'NR==1,NR==5;/^root/print $0' test.txt
示例2
FS和OFS:
# 打印以root开头到以lp开头之间,以冒号开头的的第一列和最后一列
[root@localhost ~]# awk 'BEGINFS=":";/^root/,/^lp/print $1,$NF' test.txt
[root@localhost ~]# awk -F: 'BEGINOFS="\\t\\t";/^root/,/^lp/print $1,$NF' test.txt
# 结果以 @@@分割
[root@localhost ~]# awk -F: 'BEGINOFS="@@@";/^root/,/^lp/print $1,$NF' test.txt
示例3
RS和ORS:
修改源文件前2行增加制表符和内容:
root:x:0:0:root:/root:/bin/bash hello world
bin:x:1:1:bin:/bin:/sbin/nologin test1 test2
# 以 \\t 作为分割符
[root@localhost ~]# awk 'BEGINRS="\\t";print $0' test.txt
#输出时以 \\t 作为换行符号
[root@localhost ~]# awk 'BEGINORS="\\t";print $0' test.txt
[root@localhost ~] awk 'BEGINORS="\\t";print $0' .txt
# 打印文件名
[root@localhost ~]
2)格式化输出(print+printf)
print函数 类似echo
root@localhost ~]# date | awk 'print "Month: "$2 "\\nYear: "$NF'
[root@localhost ~]# awk -F: 'print "username is: " $1 "\\t uid is: "$3' /etc/passwd
printf函数 类似echo -n
[root@localhost ~]# awk -F: 'printf "%-15s %-10s %-15s\\n", $1,$2,$3' /etc/passwd
# 右对齐
[root@localhost ~]# awk -F: 'printf "|%15s| %10s| %15s|\\n", $1,$2,$3' /etc/passwd
# 左对齐
[root@localhost ~]# awk -F: 'printf "|%-15s| %-10s| %-15s|\\n", $1,$2,$3' /etc/passwd
[root@localhost ~]# awk 'BEGINFS=":";printf "%-15s %-15s %-15s\\n",$1,$6,$NF' test.txt
%s 字符类型 strings %-20s
%d 数值类型
占15字符
- 表示左对齐,默认是右对齐
printf默认不会在行尾自动换行,加\\n
4. awk工作原理
awk -F: 'print $1,$3' /etc/passwd
-
awk使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符(RS)结束
-
每行被间隔符**:**(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始
问:awk如何知道用空格来分隔字段的呢?
答:因为有一个内部变量FS来确定字段分隔符。初始时,FS赋为空格
-
awk使用print函数打印字段,打印出来的字段会以空格分隔,因为$1,$3之间有一个逗号。逗号比较特殊,它映射为另一个内部变量,称为输出字段分隔符OFS,OFS默认为空格
-
awk处理完一行后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕
5. awk变量定义
[root@localhost ~]# awk -v tmp=666 -F: ' print tmp ' /etc/passwd
[root@localhost ~]# awk -v tmp=666 'BEGINprint tmp'
注意:
awk中调用定义的变量不需要加$
6. awk中BEGIN…END使用
- BEGIN:表示在程序开始前执行
- END:表示所有文件处理完后执行
- 语法:
BEGIN开始处理之前;处理中;END处理结束后
示例
1.打印最后一列和倒数第二列(登录shell和家目录)
[root@localhost ~]# awk -F: 'BEGINprint "shell\\t\\thome\\n====================";print $NF"\\t\\t"$(NF-1);ENDprint "===================="' test.txt
[root@localhost ~]# awk 'BEGINFS=":";print "shell\\t\\thome\\n===================";print $NF"\\t\\t"$(NF-1);ENDpirnt "==============="' test.txt
2.打印/etc/passwd里的用户名、家目录及登录shell
[root@localhost ~]# awk -F: 'BEGINOFS="\\t\\t";print"user_name\\t\\thome_dir\\t\\tshell\\n========================================"printf "%-20s %-20s %-20s\\n",$1,$(NF-1),$NF;ENDprint "========================================"' /etc/passwd
格式化输出:
echo print
echo -n printf
printf "%-15s %-20s %-20s\\n",$1,$(NF-1),$NF
7. awk和正则的综合运用
运算符 | 说明 |
---|---|
== | 等于 |
!= | 不等于 |
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
~ | 匹配 |
!~ | 不匹配 |
! | 逻辑非 |
&& | 逻辑与 |
|| | 逻辑或 |
示例
从第一行开始匹配到以lp开头行
[root@localhost ~]# awk -F: 'NR==1,/^lp/print $0' /etc/passwd
从第一行到第5行
[root@localhost ~]# awk -F: 'NR==1,NR==5print $0' /etc/passwd
从以lp开头的行匹配到第10行
[root@localhost ~]# awk -F: '/^lp/,NR==10print $0' /etc/passwd
从以root开头的行匹配到以lp开头的行
[root@localhost ~]# awk -F: '/^root/,/^lp/print $0' /etc/passwd
打印以root开头或者以lp开头的行
[root@localhost ~]# awk -F: '/^root/ || /^lp/print $0' /etc/passwd
[root@localhost ~]# awk -F: '/^root/;/^lp/print $0' /etc/passwd
显示5-10行
[root@localhost ~]# awk -F: 'NR>=5 && NR <=10 print $0' /etc/passwd
打印5-10行以nologin结尾的内容:
[root@localhost ~]# awk 'NR>=5 && NR<=10 && /nologin$/' /etc/passwd
理解;号和||的含义:
[root@localhost ~]# awk 'NR>=3 && NR<=8 || /nologin$/' /etc/passwd
[root@localhost ~]# awk 'NR>=3 && NR<=8 ; /nologin$/' /etc/passwd
打印ip地址
[root@localhost ~]# ifconfig ens33 | awk -F"[: ]+" 'NR==2print $3"\\n"$5"\\n"$7'
8.awk脚本编程
1)流程控制
if语句:
if [xxx];then
xxxx
fi
格式:
awk 选项 '正则,地址定位awk语句' 文件名
if(表达式){语句1;语句2;...}
[root@localhost ~]# awk -F: 'if($3==0) print $1"管理员"' /etc/passwd
[root@localhost ~]# awk 'BEGINif($(id -u) == 0) print "admin"'
if...else语句:
if [ xxx ];then
xxxxx
else
xxx
fi
if...else if...else语句:
格式:
if (表达式1) 语句1;语句2;... else if(表达式2) 语句;语句;... else if (表达式3) 语句;语句;... else 语句;语句;...
示例
在 CentOS7中UID从1~999号是系统账号,系统账号默认不允许登录(一般提供给一些应用使用,比如apache)
# 判断用户类型
[root@localhost ~]# awk -F: 'if($3==0) print $1,"is admin" else if($3>=1 && $3<=999) print $1,":是系统用户" else print $1,":是普通用户"' /etc/passwd
# 统计每种用户的个数
[root@localhost ~]# awk -F: ' if($3==0) i++ else if($3>=1 && $3<=999 ) j++ else n++;ENDprint "管理用户个数为:"i "\\n系统用户个数为:"j "\\n普通用户个数为"n' /etc/passwd
[root@localhost ~]# awk -F: 'if($3==0) i++ else if($3>=1 && $3<500)j++ else k++;ENDprint "管理员个数为:" i RS "系统用户个数为:" j RS "普通用户的个数为:"k' /etc/passwd
# 打印个用户名和身份
[root@localhost ~]# awk -F: ' if($3==0) print $1":是管理员" else if($3>=1 && $3<500) print $1":是系统用户" else print $1":是普通用户"' /etc/passwd
# 如果是普通用户打印默认shell,如果是系统用户打印用户名
[root@localhost ~]# awk -F: 'if($3>=1 && $3<1000) print $1 else if($3 >= 500 && $3 <= 60000) print $NF ' /etc/passwd
2)循环语句
while
# 打印1到10
[root@localhost ~]# awk 'BEGIN i=1; while(i<=10) print i;i++ '
#文件里的每一行循环打印10次:
[root@localhost ~]# awk -F: ' i=1; while(i<=10) print $0;i++ ' /etc/passwd
for
# 打印1到5
[root@localhost ~]# awk -F: ' i=1; while(i<=10) print $0;i++ ' /etc/passwd
循环示例
# 计算1到5的和
[root@localhost ~]# awk 'BEGIN for(i=1;i<=5;i++)sum+=i;print sum'
[root@localhost ~]# awk 'BEGIN for(i=1;i<=5;i++)(sum+=i);print sum'
[root@localhost ~]# awk 'BEGIN i=1;while(i<=5) (sum+=i) i++;print sum '
# 打印1到10的奇数和
for ((i=1;i<=10;i+=2));do echo $i;done|awk -v sum=0 'sum+=$0;ENDprint sum'
[root@localhost ~]# awk 'BEGIN for(y=1;y<=5;y++) for(x=1;x<=y;x++) printf x print '
1
12
123
1234
12345
# 九九乘法表
[root@localhost ~]# awk 'BEGINfor(i=1;i<=9;i++) for(j=1;j<=i;j++) printf j"*"i"="i*j"\\t"print'
循环的控制:
break 条件满足的时候中断循环
continue 条件满足的时候跳过循环
3)算数运算
+ - * / %(模) ^(幂2^3)
可以在模式中执行计算,awk都将按浮点数方式执行算术运算
[root@localhost ~]# awk 'BEGINprint 3+3'
6
[root@localhost ~]# awk 'BEGINprint 3**3'
27
[root@localhost ~]# awk 'BEGINprint 2/3'
0.666667
[root@localhost ~]# awk 'BEGINprint 3%2'
1
9. awk统计案例
- 统计/etc/passwd 中各种类型shell的数量
[root@localhost ~]# awk -F: ' shell[$NF]++ ;ENDfor (i in shell) print i,shell[i]' /etc/passwd
- 网站访问状态统计 <当前时实状态 netstat>
[root@localhost ~]#ss -antp|grep 80|awk 'states[$1]++;ENDfor(i in states)print i,states[i]'
- 统计当前访问的每个IP的数量 <当前时实状态 netstat,ss>
# netstat -ant |grep :80 |awk -F: 'ip_count[$8]++;ENDfor(i in ip_count)print i,ip_count[i] ' |sort
- 统计Apache/nginx日志中某一天的PV量 <统计日志>
# grep '27/Jul/2017' mysqladmin.cc-access_log |wc -l
- 统计Apache/Nginx日志中某一天不同IP的访问量 <统计日志>
# grep '27/Jul/2017' mysqladmin.cc-access_log |awk 'ips[$1]++;ENDfor(i in ips)print i,ips[i] ' |sort -k2 -rn |head
名词引入:
名词:VV = Visit View(访问次数)
说明:从访客来到您网站到最终关闭网站的所有页面离开,计为1次访问。若访客连续30分钟没有新开和刷新页面,或者访客关闭了浏览器,则被计算为本次访问结束。
独立访客(UV)
名词:UV= Unique Visitor(独立访客数)
说明:1天内相同的访客多次访问您的网站只计算1个UV。
网站浏览量(PV)
名词:PV=PageView (网站浏览量)
说明:指页面的浏览次数,用以衡量网站用户访问的网页数量。多次打开同一页面则浏览量累计。用户每打开一个页面便记录1次PV。
独立IP(IP)
名词:IP=独立IP数
说明:指1天内使用不同IP地址的用户访问网站的数量。同一IP无论访问了几个页面,独立IP数均为1
以上是关于shell三剑客(sed+awk)的主要内容,如果未能解决你的问题,请参考以下文章
Shell ❀ 三剑客 - Grep + Sed + Awk
Shell ❀ 三剑客 - Grep + Sed + Awk