awk
是处理文本文件的一个应用程序,几乎所有 Linux 系统都自带这个程序。
它依次处理文件的每一行,并读取里面的每一个字段。对于日志、CSV 那样的每行格式相同的文本文件,awk
可能是最方便的工具。
awk
其实不仅仅是工具软件,还是一种编程语言。不过,本文只介绍它的命令行用法,对于大多数场合,应该足够用了。
一、基本用法
awk
的基本用法就是下面的形式。
# 格式 $ awk 动作 文件名 # 示例 $ awk '{print $0}' demo.txt
上面示例中,demo.txt
是awk
所要处理的文本文件。前面单引号内部有一个大括号,里面就是每一行的处理动作print $0
。其中,print
是打印命令,$0
代表当前行,因此上面命令的执行结果,就是把每一行原样打印出来。
下面,我们先用标准输入(stdin)演示上面这个例子。
$ echo 'this is a test' | awk '{print $0}' this is a test
上面代码中,print $0
就是把标准输入this is a test
,重新打印了一遍。
awk
会根据空格和制表符,将每一行分成若干字段,依次用$1
、$2
、$3
代表第一个字段、第二个字段、第三个字段等等。
$ echo 'this is a test' | awk '{print $3}' a
上面代码中,$3
代表this is a test
的第三个字段a
。
下面,为了便于举例,我们把/etc/passwd
文件保存成demo.txt
。
root:x:0:0:root:/root:/usr/bin/zsh daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync
这个文件的字段分隔符是冒号(:
),所以要用-F
参数指定分隔符为冒号。然后,才能提取到它的第一个字段。
$ awk -F ':' '{ print $1 }' demo.txt root daemon bin sys sync
二、变量
除了$ + 数字
表示某个字段,awk
还提供其他一些变量。
变量NF
表示当前行有多少个字段,因此$NF
就代表最后一个字段。
$ echo 'this is a test' | awk '{print $NF}' test
$(NF-1)
代表倒数第二个字段。
$ awk -F ':' '{print $1, $(NF-1)}' demo.txt root /root daemon /usr/sbin bin /bin sys /dev sync /bin
上面代码中,print
命令里面的逗号,表示输出的时候,两个部分之间使用空格分隔。
变量NR
表示当前处理的是第几行。
$ awk -F ':' '{print NR ") " $1}' demo.txt 1) root 2) daemon 3) bin 4) sys 5) sync
上面代码中,print
命令里面,如果原样输出字符,要放在双引号里面。
awk
的其他内置变量如下。
FILENAME
:当前文件名FS
:字段分隔符,默认是空格和制表符。RS
:行分隔符,用于分割每一行,默认是换行符。OFS
:输出字段的分隔符,用于打印时分隔字段,默认为空格。ORS
:输出记录的分隔符,用于打印时分隔记录,默认为换行符。OFMT
:数字输出的格式,默认为%.6g
。
三、函数
awk
还提供了一些内置函数,方便对原始数据的处理。
函数toupper()
用于将字符转为大写。
$ awk -F ':' '{ print toupper($1) }' demo.txt ROOT DAEMON BIN SYS SYNC
上面代码中,第一个字段输出时都变成了大写。
其他常用函数如下。
tolower()
:字符转为小写。length()
:返回字符串长度。substr()
:返回子字符串。sin()
:正弦。cos()
:余弦。sqrt()
:平方根。rand()
:随机数。
awk
内置函数的完整列表,可以查看手册。
四、条件
awk
允许指定输出条件,只输出符合条件的行。
输出条件要写在动作的前面。
$ awk '条件 动作' 文件名
请看下面的例子。
$ awk -F ':' '/usr/ {print $1}' demo.txt root daemon bin sys
上面代码中,print
命令前面是一个正则表达式,只输出包含usr
的行。
下面的例子只输出奇数行,以及输出第三行以后的行。
# 输出奇数行 $ awk -F ':' 'NR % 2 == 1 {print $1}' demo.txt root bin sync # 输出第三行以后的行 $ awk -F ':' 'NR >3 {print $1}' demo.txt sys sync
下面的例子输出第一个字段等于指定值的行。
$ awk -F ':' '$1 == "root" {print $1}' demo.txt root $ awk -F ':' '$1 == "root" || $1 == "bin" {print $1}' demo.txt root bin
五、if 语句
awk
提供了if
结构,用于编写复杂的条件。
$ awk -F ':' '{if ($1 > "m") print $1}' demo.txt root sys sync
上面代码输出第一个字段的第一个字符大于m
的行。
if
结构还可以指定else
部分。
$ awk -F ':' '{if ($1 > "m") print $1; else print "---"}' demo.txt root --- --- sys sync
六、参考链接
- An Awk tutorial by Example, Greg Grothaus
- 30 Examples for Awk Command in Text Processing, Mokhtar Ebrahim
(完)
flyinox 说:
想必下一篇就是sed的介绍了吧,哈哈
2018年11月 7日 22:00 | # | 引用
justyy 说:
还有 grep...
2018年11月 7日 22:36 | # | 引用
业余草 说:
写的很好,看你的文章是一种享受!
2018年11月 8日 11:37 | # | 引用
Alexander 说:
上周刚看过awk,来复习一下
2018年11月 8日 11:44 | # | 引用
mifa 说:
写的很好,看你的文章是一种享受!
2018年11月 9日 02:37 | # | 引用
老贾侃球 说:
没写begin和end的用法吗...
2018年11月 9日 15:30 | # | 引用
刘米藕 说:
很不错 awk最佳入门指导
有点小问题
awk -F ':' '{if ($1 > "m") print $1}' demo.txt
并不全是输出$1第一个字符大于m的,如果$1是me这种也会输出,所以应该就是字符串间的比较
2018年11月11日 11:57 | # | 引用
sedreq 说:
能否写一篇介绍sed用法的,谢谢。
2018年11月14日 13:58 | # | 引用
狂徒大作 说:
赞!之前用ping命令,通过awk增加了时间戳。
ping 192.168.X.X | awk '{ print $0"\t" strftime("%Y:%m:%d-%H:%M:%S",systime()) fflush() } '>ping.log
2018年11月16日 16:20 | # | 引用
asdf 说:
写的很好,看你的文章是一种享受!
2018年11月24日 14:44 | # | 引用
我爱程序员 说:
字典序比较吧,大于m,m后面有任何字符都认为是大于。
2018年11月25日 21:11 | # | 引用
我的大名,必填 说:
现在有python了
2018年12月10日 18:20 | # | 引用
littleb 说:
看起来不累,非常喜欢您博文的风格。
2018年12月29日 17:20 | # | 引用
zyysasuke 说:
写的很棒,经常来拜读你的文章
2019年1月21日 15:57 | # | 引用
互联网非法移民 说:
阮老师的文章一向深入浅出
2019年1月24日 05:04 | # | 引用
谢小康 说:
看着舒服,也清晰明了,喜欢您的文章
2019年4月11日 14:04 | # | 引用
唧唧复唧唧 说:
在看NR的时候,不理解啥意思。后来想了想应该是 number row 的缩写,这样就好理解了
2019年4月20日 21:45 | # | 引用
wei 说:
第四节最后一个例子应该是print $0吧
$ awk -F ':' '$1 == "root" {print $1}' demo.txt
root
$ awk -F ':' '$1 == "root" || $1 == "bin" {print $1}' demo.txt
root
bin
2019年5月 2日 23:37 | # | 引用
青 说:
tree -if | awk '/crt$/{openssl x509 -in $1 -noout -dates }'
-in 会报格式错误 请问这个 - 该怎么处理
2019年6月 5日 09:51 | # | 引用
言身寸 说:
2019年11月14日 10:16 | # | 引用
慢慢慢时光 说:
非常棒,阅读观感很舒服,想问排版是用的什么?
2020年4月16日 10:42 | # | 引用
刘师傅 说:
我想问一下:
```
awk 文件名
#比如
awk erp
#还有下面这一行会报错
awk my.log
```
这是干啥的,也不输出,也不停止,也不报错什么的,就让我一直输入。除非Ctrl+c才能退出。老师可否帮我解答下这是咋回事呢?
```
#还有下面这一行会报错
awk my.log
```
请问我该怎么理解呢?就是awk后面接文件名怎么会这样呢?
2020年5月11日 13:58 | # | 引用
jojo 说:
@刘师傅:
没看到 awk 动作 文件名 吗。你动作都没加
2020年9月23日 21:35 | # | 引用
dingo 说:
文章能不能加个点赞功能,想点赞没地方点了。。
2021年8月12日 07:22 | # | 引用
iceui 说:
我在老外的博客上看到nr是number of records,不过还是number row好记,顺带一提NF是number of fields,FS是field separator,RS是record separator,这样下次要用的时候不用再查了。
2021年10月25日 22:03 | # | 引用
test 说:
阮老师的文章比官网教程更加通俗易懂
2021年11月26日 16:38 | # | 引用