shell三剑客(sed+awk)

Posted 郭怀远

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell三剑客(sed+awk)相关的知识,希望对你有一定的参考价值。

文章目录


一、sed

1. sed的工作流程

  1. 首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上
  2. sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会修改原文件
  3. 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——>O
  • a\\:在当前行后添加一行或多行。多行时除最后一行外,每行末尾需用“\\”续行 vim——> o
  • c\\:用此符号后的新文本替换当前行中的文本。多行时除最后一行外,每行末尾需用""续行 整行替换
# 在最后一行插入 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

  1. awk使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符(RS)结束

  2. 每行被间隔符**:**(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始

    问:awk如何知道用空格来分隔字段的呢?

    答:因为有一个内部变量FS来确定字段分隔符。初始时,FS赋为空格

  3. awk使用print函数打印字段,打印出来的字段会以空格分隔,因为$1,$3之间有一个逗号。逗号比较特殊,它映射为另一个内部变量,称为输出字段分隔符OFS,OFS默认为空格

  4. 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使用

  1. BEGIN:表示在程序开始前执行
  2. END:表示所有文件处理完后执行
  3. 语法: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统计案例

  1. 统计/etc/passwd 中各种类型shell的数量
[root@localhost ~]# awk -F: ' shell[$NF]++ ;ENDfor (i in shell) print i,shell[i]' /etc/passwd

  1. 网站访问状态统计 <当前时实状态 netstat>
[root@localhost ~]#ss -antp|grep 80|awk 'states[$1]++;ENDfor(i in states)print i,states[i]'
  1. 统计当前访问的每个IP的数量 <当前时实状态 netstat,ss>
# netstat -ant |grep :80 |awk -F: 'ip_count[$8]++;ENDfor(i in ip_count)print i,ip_count[i] ' |sort
  1. 统计Apache/nginx日志中某一天的PV量  <统计日志>
# grep '27/Jul/2017' mysqladmin.cc-access_log |wc -l
  1. 统计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)的主要内容,如果未能解决你的问题,请参考以下文章

sed后向引用取行及awk取列

Shell ❀ 三剑客 - Grep + Sed + Awk

Shell ❀ 三剑客 - Grep + Sed + Awk

Shell ❀ 三剑客 - Grep + Sed + Awk

shell 正则表达三剑客--awk

Shell文本处理工具(Linux三剑客 grep sed awk )