语法
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)
复制代码
常用参数
-F fs fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:,多个分隔符(例如:和制表符)为awk -F '[:\t]' 或者 '[:|\t]' 或者 '[":"|"\t"]',表示没发现区别
-v var=value 赋值一个用户定义变量,将外部变量传递给awk
-f scripfile 从脚本文件中读取awk命令
-m[fr] val 对val值设置内在限制,-mf选项限制分配给val的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
复制代码
摘要介绍
日常Linux流程,遇见不会的命令,先 man command
,所以 awk
的文档介绍是这么写的 mawk - pattern scanning and text processing language
用我的菜鸡英语翻译就是:模式扫描和文本处理语言。
是的,awk
并不是一个二进制程序命令,而是一门脚本语言,主要用来匹配处理文本,就像 bash
一样,同理 bash
有多个解释器: zsh
, fish
等一样,awk
也有,例如我 man awk
看到的是 mawk
,我的是Ubuntu16.04系统。因此既然 awk
是语言,mawk
是解释器而已,所以我们的操作可以是将 awk
代码直接在终端中使用,就像bash
的 echo 'hello world'
一样,也可以写成一个脚本,通过 awk -f filename
一样执行。
awk的处理方式是从输入流从逐行读取文本,然后进行 模式-动作 流程,即
pattern { action }
复制代码
小例子:
$ ls | awk '1 < 2 {print "废话"}'
废话
复制代码
这里的 1 < 2
就是 pattern 了,而 action 要包裹在 {}
里面。
使用实践-剪切获取ifconfig中的ip地址
文本如下
$ ifconfig wlp8s0
wlp8s0 Link encap:Ethernet HWaddr 5c:93:a2:76:e5:c1
inet addr:192.168.123.111 Bcast:192.168.123.255 Mask:255.255.255.0
inet6 addr: fe80::44cd:39be:6aea:d61a/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:698409 errors:0 dropped:0 overruns:0 frame:0
TX packets:353304 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:949454893 (949.4 MB) TX bytes:38261895 (38.2 MB)
复制代码
简单的剪切思路,先通过正则表达式获取ip地址那一行,awk默认的分隔符是空格,所以很明显我们的ip地址在第二列。
$ ifconfig wlp8s0 | awk '$0 ~ /inet addr/ {printf $2}'
addr:192.168.123.111
复制代码
解释如下:
$0
表示当前读取的整行,上面文本有~
表示开启正则匹配/inet addr/
正则匹配内容,表达式要写在//中间。即/pattern/{print $2}
表示匹配成功的话打印当前行的第二列。$2是内键变量,参考下面附录
接下来就很明显了,针对剪切出来的 addr:192.168.123.111
我们只需要以 :
为分隔符打印第二列就可以了。命令如下:
ifconfig wlp8s0 | awk '$0 ~ /inet addr/ {print $2}' | awk -F: '{print $2}'
复制代码
小提示:
- 当把awk代码直接放在终端中使用时,建议使用
'
而不是"
包括起来,因为"
可能会被bash解析了变量$0之类 print
和printf
的区别在于printf
可以格式化输出,但是print
自带换行
printf
示例如下
# 打印行号
$ ls / | awk '{printf "%d %s\n", NR, $0}'
行号:1 bin
行号:2 boot
行号:3 cdrom
行号:4 dev
行号:5 etc
行号:6 home
行号:7 initrd.img
行号:8 initrd.img.old
行号:9 lib
行号:10 lib64
行号:11 lost+found
行号:12 media
行号:13 mnt
行号:14 opt
行号:15 proc
行号:16 root
行号:17 run
行号:18 sbin
行号:19 snap
行号:20 srv
行号:21 sys
行号:22 tmp
行号:23 usr
行号:24 var
行号:25 vmlinuz
行号:26 vmlinuz.old
复制代码
事实上这用
nl
命令即可了。
ls / | nl
复制代码
附录-内键变量
变量 | 描述 |
---|---|
$n | 当前记录的第n个字段,字段间由FS分隔 |
$0 | 完整的输入记录 |
ARGC | 命令行参数的数目 |
ARGIND | 命令行中当前文件的位置(从0开始算) |
ARGV | 包含命令行参数的数组 |
CONVFMT | 数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组 |
ERRNO | 最后一个系统错误的描述 |
FIELDWIDTHS | 字段宽度列表(用空格键分隔) |
FILENAME | 当前文件名 |
FNR | 各文件分别计数的行号 |
FS | 字段分隔符(默认是任何空格) |
IGNORECASE | 如果为真,则进行忽略大小写的匹配 |
NF | 一条记录的字段的数目 |
NR | 已经读出的记录数,就是行号,从1开始 |
OFMT | 数字的输出格式(默认值是%.6g) |
OFS | 输出记录分隔符(输出换行符),输出时用指定的符号代替换行符 |
ORS | 输出记录分隔符(默认值是一个换行符) |
RLENGTH | 由match函数所匹配的字符串的长度 |
RS | 记录分隔符(默认是一个换行符) |
RSTART | 由match函数所匹配的字符串的第一个位置 |
SUBSEP | 数组下标分隔符(默认值是/034) |
悄悄放个个人博客地址 feng