awk处理/etc/passwd文件

前言

awk 是 linux 环境下的一个强大的编程工具,用于对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。同时它支持用户自定义函数和动态正则表达式等先进功能,可以被作为一种编程语言,可以很方便的在命令行中使用,但更多是在脚本来使用,为了熟悉这个命令,我们可以用它来尝试处理 /etc/passwd 文件学习一下常见用法。

awk处理流程

awk 这个名字来源于它的三个作者姓氏的第一个字母,分别是Alfred AhoBrian KernighanPeter 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段,分别为:

  1. 用户名:账户名字
  2. x:早期这个部分放的是用户登入密码,现在的密码是放入/etc/shadow中的
  3. UID:用户ID,0表示系统管理员,1~999保留给系统使用的ID,1000以上给一般使用者
  4. GID:组ID,0表示系统管理员,1~999保留给系统使用的ID,1000以上给一般使用者
  5. 使用者的信息说明
  6. 用户家目录:用户登入时所在的目录
  7. 默认shell:用户在登入的时候,默认使用的shell类型,如果不能使用shell,则会显示/sbin/nologin

/etc/shadow 配置文件的内容用冒号 : 隔开分为9段,分别为:

  1. 用户名
  2. 经过加密的密码( * 表示用户被锁定,!表示无加密)
  3. 最近更改过密码的日期:Linux中的日期是经过1970年1月1号开始累计的日期
  4. 密码不能修改的天数,0表示随时可以修改
  5. 密码需要重新被修改的天数,通过修改该值可以强制修改密码
  6. 密码需要变更的告警天数,7表示系统会向用户发出警告的天数
  7. 密码到期后帐号可以使用的时间
  8. 帐号失效日期,通过1970年1月1号开始累加的日期,到了时间后无论密码是否过期,该账号就不能再使用了
  9. 保留的

如果忘记自己的账户密码,该怎么处理呢?

  • 对于普通账户的密码遗失,可以通过 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
2
3
4
5
6
7
8
[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
用户名 密码 UID GID 信息 家目录 shell
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

添加行号

1
2
3
4
5
6
7
[root@VM-0-3-centos ~]# awk -F: '{printf NR"\t"$0"\n"}' /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync

打印第三行第1列和第7列

1
2
[root@VM-0-3-centos ~]# awk -F: 'NR==3{print $1"\t"$7}' /etc/passwd
daemon /sbin/nologin

打印文件总行数

1
2
[root@VM-0-3-centos ~]# awk -F: 'END{print FILENAME"\t"NR}' /etc/passwd
/etc/passwd 28

查询不能登录的用户数

1
2
[root@VM-0-3-centos ~]# awk -F: 'BEGIN{x=0} {if($7=="/sbin/nologin") x++} END{print FILENAME"\t"x}' /etc/passwd
/etc/passwd 21
1
2
[root@VM-0-3-centos ~]# awk '/nologin/' /etc/passwd | wc -l
21

查询可以登录的用户

1
2
3
[root@VM-0-3-centos ~]# awk -F: '$NF !~ /nologin$/{print $1}'  /etc/passwd
root
sync

打印UID小于300的用户

1
2
3
4
5
6
7
[root@VM-0-3-centos ~]#  awk -F: '{ if($3<300) print $1"\t"$3 }' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5

打印UID在2和6之间的用户

1
2
3
4
[root@VM-0-3-centos ~]#  awk -F: '($3>2&&$3<6){print $1"\t"$3 }' /etc/passwd
adm 3
lp 4
sync 5

进行算术运算

1
2
3
4
[root@VM-0-3-centos ~]#  awk -F: '($3*2 < 6){print $1"\t"$3 }' /etc/passwd
root 0
bin 1
daemon 2

利用条件判断统计各类用户数

1
2
3
4
[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
管理员个数: 1
普通用个数: 1
系统用户数: 26

每行数据打印3遍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@VM-0-3-centos ~]# awk -F: '{for(i=1;i<=3;i++) print NR"\t"i"\t"$0}' /etc/passwd
1 1 root:x:0:0:root:/root:/bin/bash
1 2 root:x:0:0:root:/root:/bin/bash
1 3 root:x:0:0:root:/root:/bin/bash
2 1 bin:x:1:1:bin:/bin:/sbin/nologin
2 2 bin:x:1:1:bin:/bin:/sbin/nologin
2 3 bin:x:1:1:bin:/bin:/sbin/nologin
3 1 daemon:x:2:2:daemon:/sbin:/sbin/nologin
3 2 daemon:x:2:2:daemon:/sbin:/sbin/nologin
3 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 1 adm:x:3:4:adm:/var/adm:/sbin/nologin
4 2 adm:x:3:4:adm:/var/adm:/sbin/nologin
4 3 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 1 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
5 2 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
5 3 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

统计/etc/passwd中各种类型shell的数量

1
2
3
4
5
6
7
[root@VM-0-3-centos ~]# awk -F: '{shells[$NF]++}END{ for(i in shells){print i,shells[i]}}' /etc/passwd
/bin/sync 1
/bin/bash 3
/sbin/nologin 21
/sbin/halt 1
/bin/false 1
/sbin/shutdown 1

网站访问状态统计

1
2
3
4
[root@VM-0-3-centos ~]# netstat -ant | grep :80 | awk '{access_stat[$NF]++}END{for(i in access_stat){print i, access_stat[i]}}'
LISTEN 3
CLOSE_WAIT 1
ESTABLISHED 1

生成清空arp命令的文本

1
2
3
4
5
6
7
8
[root@VM-0-3-centos ~]# arp | awk '!/Address/{print "arp -d " $1}'
arp -d 169.254.0.2
arp -d 169.254.0.3
arp -d 169.254.0.79
arp -d 172.18.0.3
arp -d 169.254.128.8
arp -d 169.254.128.9
arp -d 10.10.0.17

直接在末尾加管道 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$/' 表示最后一列不包含nologin
  • awk 还可用于待处理命令文本的预处理,先将过滤文本拼装成命令文本,然后利用管道直接通过bash执行

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

最近有些急躁,虽知欲速则不达,但压力之下确实难以平静。之所以这么拼,并不是为了卷谁,也不是为了表现给别人看,只是想有所提升超越昨天的自己,目的也非常俗套,通过提升自身来给自己的小家一个更好的生活。“一室之不治,何以天下家国为?”如果每个人都能把自己的小日子过好,则天下太平!

2022-10-30 21:24:10

Albert Shi wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客