linux工具-awk

1. 基本知识

1.1. 名称由来

awk是其设计者名字首字母.

1.2. 语法格式

awk [options] 'pattern {action}' filename

1.3. 执行流程

对如下语句:

awk 'BEGIN {action1} pattern {action2} END {action3}' filename

执行流程如下:

  1. 执行BEGIN {action1}语种块中的语句.
  2. 从文件或STDIN逐行读取, 对每一行执行pattern {action2}, 直到全部读取完成.
  3. 执行END {action3}语种块中的语句.

例子: 打印每一行, 并且在开头和结尾分别打印Start和END. print语句不带参数时就打印整行内容. $0代表整行内容.

awk ‘{printf “Start.%s.End”, $0}’ file.txt

例子:对第2列进行累加, 在BEGIN中为i赋初值, 在END中打印i(累加结果).

$ echo -e "a 1 a\na 2 a\na 3 a" | \  
> awk 'BEGIN {i=0} {i+=$2} END {print i}'  
6  

1.4. 术语解释

术语 说明
记录 awk把每一个以换行符结束的行称为一个记录, NR即记录的个数
记录中每个单词称做"域", 默认以空格或Tab分隔, NF即域的个数.

2. awk的选项: options

选项 说明
-v 参数传递, 为参数赋值
-f 指定脚本文件
-F 指定分隔符
-V 查看awk版本号

例子1:指定列分隔符

文件内容

$ cat demo.txt  
root:x:0:0:root:/root:/bin/bash  
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指定列分隔符

$ # -F和:之间没有空格  
$ awk -F: '{printf "%-6s %-9s %s\n", $1, $6, $7}' demo.txt  
root   /root     /bin/bash  
daemon /usr/sbin /usr/sbin/nologin  
bin    /bin      /usr/sbin/nologin  
sys    /dev      /usr/sbin/nologin  
sync   /bin      /bin/sync  
$   
$ # -F和:之间有空格, 这时分隔符最好放到引号中, 否则使用#等分隔时会报错.  
$ awk -F ':' '{printf "%-6s %-9s %s\n", $1, $6, $7}' demo.txt  
root   /root     /bin/bash  
daemon /usr/sbin /usr/sbin/nologin  
bin    /bin      /usr/sbin/nologin  
sys    /dev      /usr/sbin/nologin  
sync   /bin      /bin/sync  

通过-v FS指定列分隔符(FS是内置变量, 表示输入字段的列分隔符)

$ awk -v FS=: '{printf "%-6s %-9s %s\n", $1, $6, $7}' demo.txt  
root   /root     /bin/bash  
daemon /usr/sbin /usr/sbin/nologin  
bin    /bin      /usr/sbin/nologin  
sys    /dev      /usr/sbin/nologin  
sync   /bin      /bin/sync  

3. 处理文本: pattern

awk_script由pattern(模式)和Action(动作)组成.

关键词 中文名称 作用
pattern 模式 用来选取待处理的行, 可以为空, 表示处理每一行.
action 动作 对行做什么操作.

例如:

awk 'BEGIN {action1} pattern {action2} END {action3}' filename

3.1 模式pattern

有4种模式, 用来选取待处理的行, 可以为空, 表示处理每一行.

序号 模式 说明
1 /正则表达式/ 正则匹配
2 关系表达式 使用运算符进行操作, 比如字符串、数字的比较测试.
3 模式匹配表达式 用运算符:~和~!, 分别表示匹配、不匹配.
4 BEGIN/END语句块、pattern语句块 .

3.2 动作action

Action由一个或多个命令/函数/表达式组成, 它们之间用换行符或分号隔开.
action主要有以下类型:

序号 动作
1 变量或数组赋值
2 输出命令
3 内置函数
4 控制流语句

注意:

序号 语句 说明
1 BEGIN 只在开始执行一次, 是可选的, 默认无BEGIN action.
2 pattern 对匹配pattern的行进行操作, pattern是可选的, 默认对每一行进行action2, {action2}也是可选的, 默认打印匹配pattern的行, 但是pattern和{action2}必须出现一个, 不能都省略.
3 END 只在结尾执行一次, 是可选的, 默认无END action.

例子1:
输入文件内容:

$ cat a.txt  
line first    1  
line second   2  
line third    3  
line forth    4  
line fifth    5  
line sixth    6  
line seventh  7  

使用BEGIN、END等

$ # 在BEGIN的action中, 先打印一行内容, 再给i赋初值  
$ # 在遍历line的语句中, 打印第2、3列, 并对第3列累加  
$ # 在END的action中, 打印第3列的累加结果  
$ awk 'BEGIN {print "C2", "C3"; i=0} {print $2, $3; i+=$3} END {print "total=",i}' a.txt  
C2 C3  
first 1  
second 2  
third 3  
forth 4  
fifth 5  
sixth 6  
seventh 7  
total= 28  

注意:

1. 在print语句中,   
     字符串要写在双引号里,   
     字符串之间用逗号分隔,   
     变量可以直接赋初值,   
     变量使用时不能带双引号  
2. 变量赋值和使用时不需要带$号($1/$2等不受此限制)  
3. 多个action语句之间使用分号分隔.  

4. 运算符

类别 运算符 说明
赋值运算符 = 赋值语句
逻辑运算符 || 逻辑或
&& 逻辑与
正则运算符 ~ 正则匹配
~! 正则不匹配
关系运算符 <, <= 小于, 小于等于
>, >= 大于, 大于等于
== 等于
!= 不等于
算术运算符 +, - 加, 减
*, /, % 乘, 除, 取余
+, -, ! 一元加, 一元减, 逻辑非
^, ***
++, -- 自增, 自减
其他运算符 $ 字段引用
空格 字符串连接
?: 三元运算符
in 元素是否存在于数组中

例: 只处理奇数行并输出

# 说明: NR是行号, $1是第一列内容, NF是当前行列数, $(NF-1)是倒数第二列内容, $NF是最后一列内容
$ awk -F: 'NR%2==1 {printf "%s) %-6s %-9s %s\n", NR, $1, $(NF-1), $NF}' demo.txt  
1) root   /root     /bin/bash  
3) bin    /bin      /usr/sbin/nologin  
5) sync   /bin      /bin/sync  

例: 只处理$1等于root或bin的行(使用||)

$ awk -F: '$1=="root"||$1=="bin" {printf "%s) %-6s %-9s %s\n", NR, $1, $(NF-1), $NF}' demo.txt  
1) root   /root     /bin/bash  
3) bin    /bin      /usr/sbin/nologin  

5. 内置变量

范围 内置变量 说明
命令行 ARGC 命令行参数个数
ARGV 命令行参数数组
文件名 FILENAME 当前文件名
计数 FNR 各文件分别计数的行号
NF 当前行的字段个数(当前行分成了几列)
NR 行号
分隔符 FS 输入字段分隔符, 默认为空白字符
OFS 输出字段分隔符, 默认为空白字符
RS 输入记录分隔符(输入换行符)
ORS 输出记录分隔符(输出换行符)
记录 $0 完整的输入记录(当前行所有内容)
$n 当前记录的第n个字段(从1开始), 字段间由FS分隔

例: 使用NF

# NF表示字段数, 本例中NF=7, 
#    $NF即$7, 表示最后一个字段, 
#    $(NF-1), 表示倒数第二字段
$ awk -F: '{printf "%-6s %-9s %s\n", $1, $(NF-1), $NF}' demo.txt  
root   /root     /bin/bash  
daemon /usr/sbin /usr/sbin/nologin  
bin    /bin      /usr/sbin/nologin  
sys    /dev      /usr/sbin/nologin  
sync   /bin      /bin/sync  

例: 使用NR, NR表示当前行的行号

$ awk -v FS=: '{printf "%s) %-6s %-9s %s\n", NR, $1, $(NF-1), $NF}' demo.txt  
1) root   /root     /bin/bash  
2) daemon /usr/sbin /usr/sbin/nologin  
3) bin    /bin      /usr/sbin/nologin  
4) sys    /dev      /usr/sbin/nologin  
5) sync   /bin      /bin/sync  

6. 变量

awk中, 变量不需要定义就可以直接使用, 变量类型可以是数字或字符串.

例:如果第一个域匹配test, 则把第二第三个域相加并打印.

awk '$1 ~ /test/ {count=$2+$3; print count}' filename

域变量可以修改:
例: 如果第一个域等于"root", 则把它赋值为test并打印.

awk '$1=="root" {$1="test"; print}' filename

7. 条件语句

if语句

如果第三个域大于3, 则打印一个第二第三域和一个"match"字符, 各字符之间可以有空格, 也可以没有, 字符串要写到双引号中.

awk '{if ($3>3) print $2 "\t" $3 "\t" "match"}' a.txt

if-else if-else语句
有多个分支, 各分支的语句要写在大括号中.

awk '{if ($3<=2) {print "0~2"} else if ($3<=4) {print "3~4"} else {print "5~n"}}' a.txt

8. 循环语句

  1. awk有三种循环:while、for、special for
  2. 可以使用break和continue.
  3. next语句从输入文件中读取一行, 然后从头开始执行awk脚本.
  4. exit语句用于结构awk程序, 但不会略过END块.

例子:

awk '{i=1; while(i<=NF){print i, $i; i++}; print "------"}' a.txt

说明:

  1. NF是当前行(记录)的字段(域)数量, $i是第i个字段(从1开始).
  2. 注意:print语句中, i和$i是不同的东西, i是循环变量, $i是第i个字段.
  3. 本例以字段数为循环条件, 遍历每个字段并打印.

例子:

awk '{for (i=1;i<=NF;i++) {print i, $i}; print "------"}' a.txt

说明:作用同上, 将while语句改为for语句实现.

special for用来遍历关联数组.见关联数组.for(i in name) {print i, name[i]}

9. 数组

在awk中数据的下标可以是数字, 也可以是字母(称为关联数组, 类似于python中的字典).

例子:

awk '{name[i++]=$2} END {for (i=0;i<NR;i++) {print i, name[i]}}' a.txt

说明:

  1. 将每行的第二字段存入数组, 在结尾遍历数组并打印.
  2. name是一个数组, 不用声明, 直接赋值.
  3. 给数组赋值时, 直接对下标赋值, 不需要管该下标是否存在.
  4. 数组下标变量i自动初始化为0, 然后每处理一个记录自动加1.
  5. NR是当前行的行号(从1开始), 在END块中NR自动变成总行数, 用来遍历数组.

例子:

awk '/s/ {name[NR]=$2} END {for(i in name) {print i, name[i]}}' a.txt

说明:

  1. 如果某行匹配/s/, 则给数组赋值, 下标是行号, 值是$2, 在结尾遍历数组.
  2. name的下标虽然是数字, 但可以是不连续的.

10. 内置函数

https://www.gnu.org/software/gawk/manual/html_node/Built_002din.html#Built_002din

函数 作用
toupper() 字符串转为大写
tolower() 字符串转为小写
length() 返回字符串长度
substr() 返回子字符串
sin() 正弦
cos() 余弦
sqrt() 平方根
rand() 随机数

例: 使用toupper()将第一字段转为大写

$ awk -F: '{printf "%s) %-6s %-9s %s\n", NR, toupper($1), $(NF-1), $NF}' demo.txt  
1) ROOT   /root     /bin/bash  
2) DAEMON /usr/sbin /usr/sbin/nologin  
3) BIN    /bin      /usr/sbin/nologin  
4) SYS    /dev      /usr/sbin/nologin  
5) SYNC   /bin      /bin/sync  
posted @ 2020-09-10 15:29  编程驴子  阅读(109)  评论(0编辑  收藏  举报