awk 这个命令之前见过几次,但是就是不会用;上大学时 Linux 课程中老师同样讲过这个命令,可惜怎么用不记得了,梗还记着:awk —— Awkward。昨天做 Vulnhub 正好碰见,就学习下了。

awk 是一个强大的文本处理程序,它逐行处理每一个字段,即可以方便地处理包含固定个字段的文本数据 (与一张 Excel 表格类似)。整个处理过程由规则控制,规则被大括号包围,而所有的规则又被单引号 (') 包围。

字段选择

awk 最常用的方式便是显示特定的字段,日志处理中较常用。比如我们需要查看 /etc 文件夹的内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
ls -lh /etc

drwxr-xr-x 3 root root     38  7月 23 21:12 acpi
-rw-r--r-- 1 root root     44  2月 19 02:16 adjtime
drwxr-xr-x 3 root root     20  9月 11  2019 alsa
-rw-r--r-- 1 root root    541 11月  1  2019 anacrontab
drwxr-xr-x 2 root root    126  7月 23 21:12 apparmor
drwxr-xr-x 7 root root    163  7月 23 21:12 apparmor.d
lrwxrwxrwx 1 root root     15  5月 21 15:30 arch-release -> manjaro-release
drwxr-xr-x 3 root root     92  2月 19 02:36 audisp
drwxr-xr-x 2 root root     49  2月 19 02:36 audit
drwxr-xr-x 3 root root    117  3月 26 19:49 avahi

但是我们只需要权限信息和文件名称,便可以使用以下的命令:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
ls -lh /etc | awk '{print $1,$NF}'

drwxr-xr-x acpi
-rw-r--r-- adjtime
drwxr-xr-x alsa
-rw-r--r-- anacrontab
drwxr-xr-x apparmor
drwxr-xr-x apparmor.d
lrwxrwxrwx manjaro-release
drwxr-xr-x audisp
drwxr-xr-x audit
drwxr-xr-x avahi

很直观,第一个字段用 $1 表示,第 n 个字段就用 $n 表示,多个字段之间用英文逗号隔开。这里有一个比较特殊的用法,$NF 表示最后一个字段,这里的 NF 代表 number of field。同样的,$(NF-1) 表示倒数第二个字段。

分隔符选择

awk 默认读入的内容依靠空白字符分隔字段,而输出的分隔默认为空格,当然默认是可以替换的。

输出分隔

例如之前的案例,我们需要把输出的两个字段之间的分隔改称":",在规则中指定:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
ls -lh /etc | awk 'OFS=":" {print $1,$NF}'

drwxr-xr-x:acpi
-rw-r--r--:adjtime
drwxr-xr-x:alsa
-rw-r--r--:anacrontab
drwxr-xr-x:apparmor
drwxr-xr-x:apparmor.d
lrwxrwxrwx:manjaro-release
drwxr-xr-x:audisp
drwxr-xr-x:audit
drwxr-xr-x:avahi

输入分隔

假如要解析的文件是 /etc/passwd,需要查看用户名和默认的 shell,但该文件不同字段间是用 “:” 分隔的,-F 参数来指定输入的分隔符,使用如下的命令:

1
2
3
4
5
6
7
8
cat /etc/passwd | awk -F: '{print $1,$NF}'

root /bin/bash
nobody /usr/bin/nologin
dbus /usr/bin/nologin
bin /usr/bin/nologin
daemon /usr/bin/nologin
mail /usr/bin/nologin

BEGIN 和 END 规则

BEGIN 规则在读取处理文本前执行且只执行一次,END 规则在所有的文本处理结束之后执行一次,当然这两个规则是独立于文本处理规则的。有一个比较实用的用处,BEGIN 规则打印表头,END 规则打印表尾,这样就可以使表的结构更加完整。继续举上面的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
cat /etc/passwd | awk -F: 'BEGIN {print "    User & shell\n----------------------"} {print $1,$NF} END {print "----------------------"}'

    User & shell
----------------------
root /bin/bash
nobody /usr/bin/nologin
dbus /usr/bin/nologin
bin /usr/bin/nologin
daemon /usr/bin/nologin
mail /usr/bin/nologin
----------------------

条件判断

awk 文本处理过程可以加入条件判断,可以是简单的条件语句,也能是复杂的 if else 分支语句。

简单条件

假设需要查看 uid 大于等于 1000 的用户和 shell 环境:

1
2
3
4
cat /etc/passwd | awk -F: '$3 >= 1000 {print $1, $NF}'

nobody /usr/bin/nologin
haha /bin/zsh

内置函数

awk 提供了许多 内置函数,例如数值计算、大小写转换、执行系统命令等。

执行系统命令

1
2
3
awk 'BEGIN {system("echo hello")}'

hello

当然,我们可以用 awk 弹 shell,如果 awk 有 suid 权限,则可以来提权:

1
awk 'BEGIN {system("/bin/sh")}'

数值计算

1
2
3
awk 'BEGIN {print sqrt(625)}'

25

输出转化为大写

1
2
3
4
cat /etc/passwd | awk -F: '$3 >= 1000 {print toupper($1), $NF}'

NOBODY /usr/bin/nologin
HAHA /bin/zsh

参考文档

  1. https://www.howtogeek.com/562941/how-to-use-the-awk-command-on-linux/
  2. http://www.ruanyifeng.com/blog/2018/11/awk.html