shell三剑客(sed+awk)

发布于:2023-01-04 ⋅ 阅读:(547) ⋅ 点赞:(0)


一、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==5{awk语句}'	在sed中:'1,5p'
'^root/,/^ftp/{awk语句}/'	在sed中:‘/^root/,/^ftp/p’

{awk语句1;awk语句2;…}

'{print $0;print $1}'	sed中:'p'
'NR==5{print $0}'	sed中:'5p'
注意:awk命令语句间用分号隔开

BEGIN…END…

'BEGIN{awk语句};{处理中};END{awk语句}'
'BEGIN{awk语句};{处理中}'
'{处理中};END{awk语句}'

注意:如果要引用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引号里的命令清单,不要用引号保护命令,多个命令用分号间隔
BEGIN{FS=":"}
NR==1,NR==3{print $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 定义间隔符 ‘BEGIN{FS=“/”};{print $1,$3}’(以/作为分割符号)
OFS 输出记录分割符,默认换行 ‘BEGIN{FS=“:”;OFS=“@@”};{print $1,$3}’
RS 输入记录分割符,默认换行 ‘BEGIN{RS=“/”};{print $0}’
ORS 输出记录分割符,默认换行 ‘BEGIN{ORS=“\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==5{print $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 'BEGIN{FS=":"};/^root/,/^lp/{print $1,$NF}' test.txt
[root@localhost ~]# awk -F: 'BEGIN{OFS="\t\t"};/^root/,/^lp/{print $1,$NF}' test.txt
# 结果以 @@@分割
[root@localhost ~]# awk -F: 'BEGIN{OFS="@@@"};/^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 'BEGIN{RS="\t"};{print $0}' test.txt
#输出时以 \t 作为换行符号
[root@localhost ~]# awk 'BEGIN{ORS="\t"};{print $0}' test.txt
[root@localhost ~] awk 'BEGIN{ORS="\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 'BEGIN{FS=":"};{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 'BEGIN{print tmp}'

注意:
awk中调用定义的变量不需要加$

6. awk中BEGIN…END使用

  1. BEGIN:表示在程序开始前执行
  2. END:表示所有文件处理完后执行
  3. 语法:BEGIN{开始处理之前};{处理中};END{处理结束后}

示例
1.打印最后一列和倒数第二列(登录shell和家目录)

[root@localhost ~]# awk -F: 'BEGIN{print "shell\t\thome\n===================="};{print $NF"\t\t"$(NF-1)};END{print "===================="}' test.txt

[root@localhost ~]# awk 'BEGIN{FS=":";print "shell\t\thome\n==================="};{print $NF"\t\t"$(NF-1)};END{pirnt "==============="}' test.txt

2.打印/etc/passwd里的用户名、家目录及登录shell

 [root@localhost ~]# awk -F: 'BEGIN{OFS="\t\t";print"user_name\t\thome_dir\t\tshell\n========================================"}{printf "%-20s %-20s %-20s\n",$1,$(NF-1),$NF};END{print "========================================"}' /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==5{print $0}' /etc/passwd
从以lp开头的行匹配到第10行       
[root@localhost ~]# awk -F: '/^lp/,NR==10{print $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==2{print $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 'BEGIN{if($(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++}};END{print "管理用户个数为:"i "\n系统用户个数为:"j "\n普通用户个数为"n}' /etc/passwd
[root@localhost ~]# awk -F: '{if($3==0) {i++} else if($3>=1 && $3<500){j++} else {k++}};END{print "管理员个数为:" 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};END{print 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 'BEGIN{for(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 'BEGIN{print 3+3}'
6
[root@localhost ~]# awk 'BEGIN{print 3**3}'
27
[root@localhost ~]# awk 'BEGIN{print 2/3}'
0.666667
[root@localhost ~]# awk 'BEGIN{print 3%2}'
1

9. awk统计案例

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

  1. 网站访问状态统计 <当前时实状态 netstat>
[root@localhost ~]#ss -antp|grep 80|awk '{states[$1]++};END{for(i in states){print i,states[i]}}'
  1. 统计当前访问的每个IP的数量 <当前时实状态 netstat,ss>
# netstat -ant |grep :80 |awk -F: '{ip_count[$8]++};END{for(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]++};END{for(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


网站公告

今日签到

点亮在社区的每一天
去签到