GNU awk 的使用及相关练习

GNU awk,简称gawk,是一种模式扫描和处理语言。本文介绍了gawk的基本用法,包括变量、输出命令、模式匹配以及常用控制语句。通过实例展示了如何设置分隔符、使用内置变量如FS、OFS、RS、ORS,以及print和printf命令。还探讨了awk中的数组和函数,如rand()、length()、sub()和split(),帮助读者掌握awk的实战技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

gawk

gawk - pattern scanning and processing language 来自手册页的介绍:模式扫描和处理语言。awk 扫描文件中的每一行,查找在命令行中有无相匹配的模式;若有则进行编程步骤,若无则进行下一行的处理。

在 CentOS 7 中执行命令

ls -l `which awk
# 即可知 awk 为 gawk 的链接文件,因为 gawk 为 awk 的 GNU 版本

基本用法

AWK是一种处理文本文件的语言。它将文件作为记录序列处理。在一般情况下,文件内容的每行都是一个记录。每行内容都会被分割成一系列的域,因此,我们可以认为一行的第一个词为第一个域,第二个词为第二个,以此类推。AWK程序是由一些处理特定模式的语句块构成的。AWK一次可以读取一个输入行。对每个输入行,AWK解释器会判断它是否符合程序中出现的各个模式,并执行符合的模式所对应的动作。
——阿尔佛雷德·艾侯,The A-Z of Programming Languages: AWK

gawk [option] 'program' FILE ...
# 其中 program: PATTERN{ACTION STATEMENTS}

上面的 program 即为由模式与命令语句所编写的程序,action 意为对匹配到的模式执行的一系列命令。awk 将输入分为多个 record,默认以换行符分割。而后对每条 recoed 进行模式扫描,对匹配的 record 进行 action 操作。

常用选项:

  • -F:指明输入时用到的分隔符
  • -v var=value:自定义变量

awk 变量:

内建变量:

  • FS:field separator,域分隔符;将输入的 record 分为多个 fields,其默认为空白字符,也可以进行自定义。
  • OFS:output field separator,输出域分隔符;默认为空格。
awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd
  • RS:record separator,输入记录分隔符;默认输入的每一行为一个 record,因此默认的 RS 为换行符。
  • ORS:output record separator,输出记录分隔符;执行 print 命令时的分隔符。
  • NF:the number of fields,当前 record 中域的个数。
awk '{print NF}' /etc/fstab # 做变量时不需要加 $ 进行引用
awk '{print $Nf}' /etc/fstab # 加上 $ 后意为打印最后一个域的内容
  • NR:the number of input records,输入记录的数量。

两个输出命令

print 命令:

print item1, item2, ...

以逗号分隔各 item,其可以为数值、字符串、变量或是域;若省略 item 则表示打印 $0 即整行输出。

awk 'BEGIN{print "Hello World"}'

printf 命令:
格式化输出,使用类似于 C 语言中的用法。

printf FORMAT,item1,item2, ...

其中 FORMAT 必须给出,若要换行须使用 \n,常用有 %d,%f;以及修饰符 - 使其左对齐。

PATTERN

到这你已经看见了,每个 awk 语句都包含有 PATTERN,同时模式在控制着 awk 的执行。

  • empty:空模式,匹配每一行。
  • /regular expression/:仅处理能够被此处的模式所匹配到的行。
  • BEGIN:仅在开始处理文件中的文本之前执行一次。
  • END:仅在文本处理完成之后执行一次,有在添加表头表格尾部时使用。

常用 action 中的控制语句

  • if-else:使用场景为对 awk 取得的整行或某个字段做条件判断。
awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd
# 以#为分隔符分割/etc/passwd 文件,找出 UID 大于 1000 的用户并打印其用户名与 UID

awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
# 以#为分隔符分割/etc/passwd 文件,找出其中最后一字段为"/bin/bash"的行,并打印其第一字段

awk '{if(NF>5) print $0}' /etc/fstab
# 找出/etc/fstab 文件中,域大于 5 个的记录

df -h |awk -F% '/^\/dev/{print $1}' |awk '{if($NF>20) print $1}'
# 以易读的方式列出磁盘的使用情况,并 awk 出以/dev 开头的记录,后再 awk 出最后一字段即使用量大于 20 的设备
  • while 循环:对一行内的多个字段逐一做类似处理时使用;对数组中的各元素统一处理时使用
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i);i++}}' /etc/grub2.cfg
# 先在文件中匹配出以多个空白字符后跟linux16开头的记录,在打印出每个字段的内容及其长度

awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)};i++}}' /etc/grub2.cfg
# 先在文件中匹配出以多个空白字符后跟linux16开头的记录,在打印出每个长度大于 7 的字段的内容及其长度
  • for 循环:语法如下
for(variable assigment;condition;iteration process) {for-body}

awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
# 先在文件中匹配出以多个空白字符后跟linux16开头的记录,在打印出每个字段的内容及其长度

#同时 for 也能够遍历数组中的元素:
for(var in array_name) {for-body}
  • next:前结束对本行的处理而直接进入下一行
awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
# 在/etc/passwd 文件中 awk 时,遇见奇数行则跳过,即打印偶数行

数组

awk 中使用更多的为关联数组,即 array[index-expression];同时我们需要注意,索引可使用任意字符串,但字符串要使用双引号。如果某数组元素事先不存在,则在引用时 awk 会自动创建此元素,并将其初始化为“空串”。

awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'
# 使用 for 循环遍历数组中的每个元素

netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) {print i,state[i]}}'
# 匹配以 tcp 开头并锚定在词尾的记录,同时 state 数组的索引为当前 record 最后一个字段的字符串,并以之完成自增即计数操作

awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab
# 匹配以 UUID 开头的记录,同时 fs 数组的索引为当前 record 的第三字段的字符串,并以之完成自增即计数操作

awk '{for(i=1;i<=NF;i++) {count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab
# 统计指定文件中每个单词出现的次数

函数的使用

rand()
length()
sub()
split()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值