Linux三剑客之awk

546人浏览   2023-10-23 14:33:08

Linux三剑客之awk

awk简介

awk,全称GNU awk

此命令的设计者有 3 位,他们的姓分别是 Aho、Weingberger 和 Kernighan,awk 就取自这 3 为大师姓的首字母。

awk不仅仅是Linux中的一个命令,而且还是一种编程语言,可以用来处理和生成报告(excel)。它是Linux中最强大的文本处理工具,没有之一。

[root@m01 ~]#ls -l `which awk`
lrwxrwxrwx. 1 root root 4 Sep  9 18:10 /usr/bin/awk -> gawk


一般我们使用awk,都是当做命令使用,所以我们称之为单行脚本那么awk能不能写脚本呢,必然可以,在linux系统中就有很多的awk脚本

[root@m01 ~]# find /usr/share/ -type f -name '*.awk'
/usr/share/awk/assert.awk
/usr/share/awk/bits2str.awk
/usr/share/awk/cliff_rand.awk
...


awk语法格式

# 语法格式
awk [选项] '模式{动作1;动作2}' 文件
有多个动作时;隔开


# 选项
-F 指定分隔符
-v 传递命令行的变量   定义或修改一个awk内部的变量


# 简单例子
显示/etc/passwd行号,第一列,第三列和最后一列
[root@m01 ~]# awk -F: '{print $1,$3,$NF}' /etc/passwd


awk的模式和动作

模式

[root@m01 ~]# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
...


[root@m01 ~]# awk -F: 'NR==1{print$1,$3}' /etc/passwd   //先取第1行,再取列
root 0


比如上面这条命令'NR==1{print $1,$3}'对应就是'模式{动作}' 相当于:'条件{指令}'


## 模式有:
# 比较表达式
NR==1
NR>=10
NR<=100
NR>=1 && NR<=10
$1>=100


比如,取etc/passwd的1-3行
[root@m01 ~]# awk 'NR<=3' /etc/passwd




# 范围模式
精确匹配行号:从第10行到第20行
NR==10,NR==20
[root@m01 ~]# awk 'NR==1,NR==3' /etc/passwd (效果同上)


# 精确匹配字符串:从该字符串的行到另一个字符串所在行
'/root/,/zls/'
'/从哪个字符串所在行/,/到那个字符串所在行/'  #中间的行都包含进去


比如:取出包含root的行,要讲要取的内容用//包含
[root@m01 ~]# awk '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin




# 模糊匹配字符串:从含有该字符串所在行到含有另一字符串所在行
'$1~/oo/,$1~/zl/'




## 正则表达式模式
# 正则表达式写法   也是用//包含
'/正则表达式/flag'  
'$1~/正则表达式/flag'
'$1!~/正则表达式/flag'


只不过我们在awk中很少使用flag






## 特殊模式:
BEGIN 和 END


动作

  • print 打印
  • gsub 替换
  • gsub/被替换的内容/,"要替换的" ,$n指定要替换的列
  • 变量赋值
  • 统计计算

有多个动作时用;隔开


awk的常见变量

内置变量

含义

$0

当前整行记录

$n

当前记录的第n个列,字段间由FS或-F选项指定分隔符

NF

Number of Field 所有列数。即共有多少列

$(NF-n)

倒数第n+1列

NR

Number of Record 已经读出的记录数,就是行号。从1开始

RS

Record Separator -vRS可指定每行(每个记录)结束的标识,默认是回车(换行符)

FS

Field Separator -vFS(-F)指定读取列时的分隔符(默认是空格)

OFS

Output Field Separator 输出时候的分隔符,默认是空格


awk执行流程

  • 读取文件前
  • BEGIN{} - 读取文件之前,先判断命令的选项:-F,-v
    - 如果写了BEGIN{},再执行BEGIN{}里面的动作
  • 读取文件时
  • {}
    • awk读取文件时(和sed一样),一行一行读取文件
    • 读取一行之后,判断是否满足条件'NR==3{print $0}',满足后再执行{}中的动作
    • 如果不满足条件,awk继续读取下一行,直到满足条件或者到文件的最后一行

  • 读取文件后
  • END{}完成读取所有文件后,执行END{}里面的动作


任写哪个阶段都行,但END阶段不能单独使用

[root@m01 ~]# awk 'BEGIN{print 1+3}'
4
[root@m01 ~]# awk 'END{print 1+3}' 不行,后面要有文件名

注意:awk中单引号和双引号区别很大,双引号引字符串,单引号调用awk的变量

# 坑,在awk无法直接调用bash变量
[root@m01 08:59:36 ~]# awk "/$HOSTNAME/{print $1}"
必须外面单引号里面双引号


[root@m01 ~]# awk -F: 'BEGIN{print "用户名","UID"}{print $1,$3}END{print "文件读取完毕"}' /etc/passwd
用户名 UID
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
...
[root@m01 ~]# awk -F: 'BEGIN{print "用户名","UID"}{print $1,$3}END{print "文件读取完毕"}' /etc/passwd|column -t
用户名           UID
root             0
bin              1
daemon           2
adm              3
lp               4
sync             5
shutdown         6
halt             7
mail             8
operator         11
games            12
ftp              14
nobody           99
...

相关推荐