前言
awk
是 linux 环境下的一个强大的编程工具,用于对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。同时它支持用户自定义函数和动态正则表达式等先进功能,可以被作为一种编程语言,可以很方便的在命令行中使用,但更多是在脚本来使用,为了熟悉这个命令,我们可以用它来尝试处理 /etc/passwd
文件学习一下常见用法。
awk处理流程
awk
这个名字来源于它的三个作者姓氏的第一个字母,分别是Alfred Aho
、Brian Kernighan
、Peter Weinberger
,常用的版本是 gawk
, 它是awk的GNU版本,提供了Bell实验室和GNU的一些扩展。
awk 工作流程可分为三个部分:
- 读输入文件之前执行的代码段(GEGIN块,由BEGIN关键字标识,可选)
- 主循环执行输入文件的代码段(BODY块,可选)
- 读输入文件之后的代码段(END块,由END关键字标识,可选)
命令结构:
1 | awk 'BEGIN{ commands } pattern{ commands } END{ commands }' |
开始块(BEGIN)
1 | BEGIN {awk-commands} |
开始块部分是可选的,可以没有开始块部分,如果存在必须以 BEGIN
开头
开始块就是在程序启动的时候执行的代码部分,并且它在整个过程中只执行一次,我们可以在开始块中初始化一些变量。
主体块(BODY)
1 | pattern {awk-commands} |
默认情况下,对于输入的每一行,awk 都会执行命令,我们可以通过 pattern 将其限定在指定的模式中,这部分也是可选的,不存在也是可以的,不过不存在主体的脚本用处不大。
结束块(END)
1 | END {awk-commands} |
结束块部分是可选的,可以没有结束块部分,是在程序结束时执行的代码。 如果存在必须以 END
开头
/etc/passwd文件
起初 /etc/passwd 文件包含了用户名和密码,但是由于该文件允许所有用户读取,易导致用户密码泄露,因此 Linux 系统将用户的密码信息从 /etc/passwd 文件中分离出来,并单独放到了/etc/shadow 文件中,此文件只有 root 用户拥有读权限,其他用户没有任何权限,这样就一定程度上保证了用户密码的安全性。
/etc/passwd
配置文件的内容用冒号 :
隔开分为7段,分别为:
- 用户名:账户名字
- x:早期这个部分放的是用户登入密码,现在的密码是放入/etc/shadow中的
- UID:用户ID,0表示系统管理员,1~999保留给系统使用的ID,1000以上给一般使用者
- GID:组ID,0表示系统管理员,1~999保留给系统使用的ID,1000以上给一般使用者
- 使用者的信息说明
- 用户家目录:用户登入时所在的目录
- 默认shell:用户在登入的时候,默认使用的shell类型,如果不能使用shell,则会显示/sbin/nologin
/etc/shadow
配置文件的内容用冒号 :
隔开分为9段,分别为:
- 用户名
- 经过加密的密码( * 表示用户被锁定,!表示无加密)
- 最近更改过密码的日期:Linux中的日期是经过1970年1月1号开始累计的日期
- 密码不能修改的天数,0表示随时可以修改
- 密码需要重新被修改的天数,通过修改该值可以强制修改密码
- 密码需要变更的告警天数,7表示系统会向用户发出警告的天数
- 密码到期后帐号可以使用的时间
- 帐号失效日期,通过1970年1月1号开始累加的日期,到了时间后无论密码是否过期,该账号就不能再使用了
- 保留的
如果忘记自己的账户密码,该怎么处理呢?
对于普通账户的密码遗失,可以通过 root 账户使用 passwd 命令重新设置密码解决,
passwd username
。如果 root 账号的密码遗失,则需要重新启动进入单用户模式,系统会提供 root 权限的 bash 接口,此时可以用 passwd 命令修改账户密码。或者通过挂载根目录,修改
/etc/shadow
文件将 root 密码清空,无密码即登陆后再使用 passwd 命令配置 root 密码。
awk 常用处理
字段分割及相关变量
- $1,$2,$3…$n:awk中用该顺序形式表示files中每行以间隔符号分割的各列的不同字段
- $0:表示文本本身
- NF:表示当前记录的字段数(列数)
- $NF:最后一列
- $(NF-1):倒数第二列
- FNR/NR:行号
- FILENAME:文件名
- “\t”:制表符
- RS:换行符
- “”: 打印字符串
- FS:定义间隔符
- ~:匹配,与==相比不是精确比较
- !~:不匹配,不精确比较
- ==:等于,必须全部相等,精确比较
- /[0-9][0-9]+/:两个或两个以上数字
- -F’[:#]’:定义两个分隔符
常用处理
添加表头
1 | [root@VM-0-3-centos ~]# awk -F: 'BEGIN{print"用户名\t密码\tUID\tGID\t信息\t家目录\tshell"}{printf $1"\t"$2"\t"$3"\t"$4"\t"$5"\t"$6"\t"$7"\n"}' /etc/passwd |
添加行号
1 | [root@VM-0-3-centos ~]# awk -F: '{printf NR"\t"$0"\n"}' /etc/passwd |
打印第三行第1列和第7列
1 | [root@VM-0-3-centos ~]# awk -F: 'NR==3{print $1"\t"$7}' /etc/passwd |
打印文件总行数
1 | [root@VM-0-3-centos ~]# awk -F: 'END{print FILENAME"\t"NR}' /etc/passwd |
查询不能登录的用户数
1 | [root@VM-0-3-centos ~]# awk -F: 'BEGIN{x=0} {if($7=="/sbin/nologin") x++} END{print FILENAME"\t"x}' /etc/passwd |
1 | [root@VM-0-3-centos ~]# awk '/nologin/' /etc/passwd | wc -l |
查询可以登录的用户
1 | [root@VM-0-3-centos ~]# awk -F: '$NF !~ /nologin$/{print $1}' /etc/passwd |
打印UID小于300的用户
1 | [root@VM-0-3-centos ~]# awk -F: '{ if($3<300) print $1"\t"$3 }' /etc/passwd |
打印UID在2和6之间的用户
1 | [root@VM-0-3-centos ~]# awk -F: '($3>2&&$3<6){print $1"\t"$3 }' /etc/passwd |
进行算术运算
1 | [root@VM-0-3-centos ~]# awk -F: '($3*2 < 6){print $1"\t"$3 }' /etc/passwd |
利用条件判断统计各类用户数
1 | [root@VM-0-3-centos ~]# awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理员个数: "i; print "普通用个数: "k; print "系统用户数: "j}' /etc/passwd |
每行数据打印3遍
1 | [root@VM-0-3-centos ~]# awk -F: '{for(i=1;i<=3;i++) print NR"\t"i"\t"$0}' /etc/passwd |
统计/etc/passwd中各种类型shell的数量
1 | [root@VM-0-3-centos ~]# awk -F: '{shells[$NF]++}END{ for(i in shells){print i,shells[i]}}' /etc/passwd |
网站访问状态统计
1 | [root@VM-0-3-centos ~]# netstat -ant | grep :80 | awk '{access_stat[$NF]++}END{for(i in access_stat){print i, access_stat[i]}}' |
生成清空arp命令的文本
1 | [root@VM-0-3-centos ~]# arp | awk '!/Address/{print "arp -d " $1}' |
直接在末尾加管道 bash
就可以执行了,arp | awk '!/Address/{print "arp -d " $1}'| bash
这是一种通用的生成处理命令的方式,先生成命令文本,然后作为bash输入,执行即可。
总结
awk
处理流程分为3个阶段,BEGIN块、BODY块、END块,其中BEGIN块和END块都执行一次,BODY块对每一行输入执行一次awk
的3个处理块都是可选的,对于待处理的文件,一般至少会包含BODY块awk
中BODY块的 pattern 用于行过滤,/pattern/
表示匹配,/!pattern/
表示不匹配awk
中BODY块的中也可对指定字段判断是否包含,'$1 ~ /root/'
表示第一列包含root,'$NF !~ /nologin$/'
表示最后一列不包含nologinawk
还可用于待处理命令文本的预处理,先将过滤文本拼装成命令文本,然后利用管道直接通过bash执行
最近有些急躁,虽知欲速则不达,但压力之下确实难以平静。之所以这么拼,并不是为了卷谁,也不是为了表现给别人看,只是想有所提升超越昨天的自己,目的也非常俗套,通过提升自身来给自己的小家一个更好的生活。“一室之不治,何以天下家国为?”如果每个人都能把自己的小日子过好,则天下太平!
2022-10-30 21:24:10