awk命令——《Linux日常》

一、介绍

  • awk是一种编程语言(解释性语言,不需要编译),用于数据截取和报告的工具
  • awk自动搜索输入的文件,并把每个输入行切分成多个字段(字段:根据分隔符分割成的单元)
  • 擅长处理数据库和表型数据。适合编写短小一次性程序
  • centos默认的awk使用的是gawk,系统将awk通过软链接来指向gawk
  • 可以使用新的内置函数和变量
  • 在缺省的情况下,它使用扩展的正则表达式
  • awk不需要声明变量的数据类型,它内置字符串类型和数值类型

二、命令格式

awk [OPTIONS] [--] program filename_list
选项 说明
-f program -file 指定包含了awk命令的文件,不是从命令行参数中去读取 可以通过-f选项指定多个包含awk命令文件
-F ‘fs’ --field -separator 指定分隔符即为定义FS变量对应的值
-v var=val 在程序开始之前,将val这个值赋给var这个变量
-d[file] 将全局变量的类型和最终值排序,并将排序好后的结果打印输出到文件中
-V 显示awk的版本

三、使用方法及范例

3.1 awk的核心

  • PROGRAM——'pattern{action}'

3.2 关于pattern { action }的说明:

  • patternaction并非同时存在,可以省略其中一个
  • 如果action被省略,默认动作是将每个匹配的行输出
  • 如果pattern被省略,对于每行都会执行动作

awk基本操作流程:

  1. 从输入流中读取一行内容,然后使用pattern{action}去处理
  2. 对读取的行进行扫描搜索,搜索行中是否有内容被pattern匹配
  3. 如果行被pattern匹配成功,则执行动作{action};如果行中内容不被pattern匹配,则不执行
  4. 继续从输入流中读取新的一行,重复上述几个步骤

例一:简单理解awk

问题描述:

  • file1文件第一列为员工名字,第二列为时薪,第三列为工作时长
  • 打印输出员工的名字、时薪和工作时长

执行命令:

[root@CentOS7 commands]# cat file1
Sam	50	8
Jiangle	55	9
Tom	40	6
Tim	60	9

[root@CentOS7 commands]# awk '{print $1,$2,$3}' file1
Sam	50	8
Jiangle	55	9
Tom	40	6
Tim	60	9

说明:

  • awk命令后面的程序用单引号引起来,单引号后面的部分为输入文件
  • 单引号中包围的内容是一个awk程序(program),即模式-动作语句(pattern-action)

3.3 pattern详细说明

  • pattern,即模式,是决定awk程序中定义的动作action是否能够被执行的关键
  • pattern支持的规则:正则表达式,字符串与数字比较,流程控制语句

例二:pattern——控制输出条件1

问题描述:

  • file1文件第一列为员工名字,第二列为时薪,第三列为工作时长
  • 打印输出时薪大于等于50的员工名字和总薪资

执行命令:

[root@CentOS7 commands]# cat file1
Sam	50	8
Jiangle	55	9
Tom	40	6
Tim	60	9

[root@CentOS7 commands]# awk '$2>=50 {print $1,$2*$3}' file1
Sam 400
Jiangle 495
Tim 540

说明:

  • 其中模式pattern'$2>=50',表示扫描每一个输入的行,如果第二列大于0,则执行动作action,否则不执行action
  • 动作action'{ print $1,$2*$3 }',模式匹配成功后执行的对应动作,该动作用于打印输出第一个字段和第二、三字段的乘积

模式表示方式汇总:

模式 说明
/regexp/ 正则之字符串匹配模式/regexp/(拓展的正则表达式)
例如:expression ~ /regexpr/表示当前输入行包含能被regexpr匹配的子字符串时,该模式被匹配
relational expression 当表达式拥有一个数值形式的值,运算符要求一个字符串值,则awk会将该数值自动转换成字符串
当表达式拥有一个字符串形式的值,运算符要求一个数值,则awk会将该字符串值自动转换成数值
关于表达式真与假的说明:如果一个表达式,对当前述入行的求值结果非零或不为空,那么该行就被匹配
如果比较字符串,比较时是逐字符依赖ASCII字符表比较
pattern 1 && pattern2 只有当pattern1和pattern2都匹配了,才会执行action
pattern1 || pattern2 当pattern1和pattern2其中一个匹配了,就会执行action

比较运算符汇总

运算符 说明
< 小于
<= 小于等于
== 等于
!= 不等于
> 大于
>= 大于等于
~ 匹配
!~ 不匹配

表达式运算符汇总(也可以用在action)

操作 运算符 举例
赋值 =、+=、-=、*=、/=、^= sum+=i,即sum=sum+i
条件表达式 ?: x?y:z,若x为真则为y,否则为z
逻辑或 || x\|\|y,x或y为真,则表达式为真
逻辑与 && x&&y,x与y为真,则表达式为真
数组成员 in i in a,i在a中
字段 $ $1 表示输入行的第一个字段
组合 ( ) $(2+1) 表示第三个字段
匹配
不匹配
~
!~
自增
自减
++

例三:pattern——控制输出条件2

问题描述:

  • 打印输出file2第一和二个字段都为数字或第三和四个字段都为字母的行

执行命令:

[root@CentOS7 commands]# cat file2
1 2 3 4
1 2 a b
a 1 4 3
1 a 2 b

[root@CentOS7 commands]# awk '($1~/[0-9]/ && $2~/[0-9]/)||($3~/[a-zA-Z]/ && $4~/[a-zA-Z]/)' file2
1 2 3 4
1 2 a b

说明:

  • $1~/[0-9]/表示匹配第一列中包含数字0-9,其中的pattern为[0-9]
  • $3~/[a-zA-Z]/表示匹配任意大小写字母

3.4 action详细说明

关键字和变量

  • 关键字
关键字 说明
BEGIN 放在程序开头,当awk从输入流中读取数据之前,BEGIN语句开始执行(初始化),可以执行多个BEGIN
END 放在程序末尾,当所有输入流被读取完毕,END语句开始执行(扫尾),可以执行多个END
  • 内建变量
变量 说明
$n 当前记录的第n个字段,字段间由FS分隔
$0 完整的输入记录
FS Field Separator,表示字符分隔符,即读取输入流时,以FS作为字段分隔的依据,默认为空格符
RS Record Separator,表示记录分隔符,即读取输入流时,以RS作为记录分隔的依据,默认是一个换行符
OFS Output Field Separator,表示输出字段分隔符,默认为空格符
ORS Output Record Separator,表示输出记录分隔符,默认为换行符
NF Number of Field,表示每一行的字段数目
NR Number of Row,记录读取的行的行号
IGNORECASE IGNORECASE如果为真,则进行忽略大小写的匹配

例四:action——控制语句输出1

问题描述:

  • file1文件第一列为员工名字,第二列为时薪,第三列为工作时长
  • 打印输出每一个员工名字和总薪资,添加一个表头说明,中间用":"隔开

执行命令:

[root@CentOS7 commands]# cat file1
Sam	50	8
Jiangle	55	9
Tom	40	6
Tim	60	9

[root@CentOS7 commands]# awk 'BEGIN{OFS=":";ORS="\n\n"} BEGIN{print "name:total_salary"} {print $1,$2*$3}' file1
name:total_salary

Sam:400

Jiangle:495

Tom:240

Tim:540

说明:

  • 第一个BEGIN语句是控制输出字段分隔符OFS和输出记录分隔符ORS
  • 第二个BEGIN语句是输出字符串"name:total_salary"
  • 执行完两个BEGIN后,awk再从输入流中读取处理数据
  • 注意:对变量FSOFSORS赋值时,需要使用双引号,不能没有引号或使用单引号

格式化输出语句

action的格式化输出语句通过printf实现,在print语句中,多个变量之间使用逗号作为分隔符,对变量进行分隔

  • printf语法格式:printf(format,expression1,expression2…)
  • 参数format包含“%”、对齐方式、格式控制字符、字符串最大宽度

printf格式控制字符

格式字符 说明
- 左对齐修饰符,默认为右对齐
# 显示8 进制整数时在前面加个0
显示16 进制整数时在前面加0x
+ 显示使用d 、e 、f 和g 转换的整数时,加上正负号±
0 用0而不是空白符来填充所显示的值,即用字符’0’填充
%c 表示一个ASCII字符
%s 表示一个字符串
%d 表示一个十进制整数
%u 表示一个无符号的十进制数
%x 表示一个十六进制数
%o 表示一个八进制数
%f 表示一个浮点数
%e 用科学计数法(e 记数法),表示一个浮点数
%g 选择e或f中较短的一种形式

上面差不多就是printf的常用格式输出了,下面是一些常用的复合。就是啊,附和!!!

在这里插入图片描述

复合格式字符 说明
%10d 十进制数占10列
%010d 十进制数占10列,前面用字符’0’填充
%+10d 十进制数占10列,包含数值的符号(±)
%#10x 十六进制数占10列,显示前缀0x
%-10.3f 浮点数左对齐占10列,保留3位小数
%0+10.3f 浮点数右对齐占10列,保留3位小数,显示符号,左补齐填充字符’0’
%10s 字符串右对齐,占10列
%-10s 字符串左对齐,占10列

例五:action——控制语句输出2

问题描述:

  • file1文件第一列为员工名字,第二列为时薪,第三列为工作时长
  • 打印输出每一个员工编号(所在行数即为编号)、名字和总薪资;员工编号左对齐占5列,名字右对齐占10列,总薪资占10列右对齐保留两位小数

执行命令:

[root@CentOS7 commands]# cat file1
Sam	50	8
Jiangle	55	9
Tom	40	6
Tim	60	9

[root@CentOS7 commands]# awk 'BEGIN{printf "%-5s%10s%10s\n","ID","NAME","SALARY"}{printf("%-5d%10s%10.2f\n",NR,$1,$(NF-1)*$NF))}' file1
ID         NAME    SALARY
1           Sam    400.00
2       Jiangle    495.00
3           Tom    240.00
4           Tim    540.00

说明:

  • NF表示当前行的字段数(列数),$NF表示当前行的最后一个字段值
  • 这里的$(NF-1)*$NF$2*$3相同
  • printf不会自动换行,需要添加换行符"\n"才能换行

四、awk进阶

4.1 输出重定向

4.1.2 输出重定向到文件

  • 使用>>重定向,不清空文件内容,将内容追加到文件尾部
  • 使用>重定向,清空文件内容,再把内容写入文件

例六:输出重定向到文件

问题描述:

  • file1文件第一列为员工名字,第二列为时薪,第三列为工作时长
  • 将时薪大于等于50的员工的信息保存到new_file1

执行命令:

[root@CentOS7 commands]# cat file1
Sam	50	8
Jiangle	55	9
Tom	40	6
Tim	60	9

[root@CentOS7 commands]# awk '$2>=50 {print $0 > "new_file1"}' file1

[root@CentOS7 commands]# cat new_file1 
Sam	50	8
Jiangle	55	9
Tim	60	9

说明:

  • 重定向时,文件名必须要用双引号引起来,否则会被当作一个未初始化的变量
  • >重定向时,会覆盖目标文件的内容

4.1.2 输出重定向到管道

  • 使用管道命令|进行数据的处理

例七:输出重定向到管道

问题描述:

  • file1文件第一列为员工名字,第二列为时薪,第三列为工作时长
  • 按照总薪资降序进行排序,名字占10列左对齐,时薪占10列左对齐,工作时长占10列左对齐,总薪资占10列左对齐

执行命令:

[root@CentOS7 commands]# cat file1
Sam	50	8
Jiangle	55	9
Tom	40	6
Tim	60	9

[root@CentOS7 commands]# awk '{printf("%-10s%-10d%-10d%-10d\n",$1,$2,$3,$2*$3) | "sort -nrk 4 "}' file1
Tim       60        9         540       
Jiangle   55        9         495       
Sam       50        8         400       
Tom       40        6         240       

说明:

  • 语句{printf(...) | "sort..."}中的sort必须用双引号引起来
  • sort-n表示按照字符串的数值顺序比较;-r表示逆序比较,默认为升序;-k 4 表示以第4个字段(第4列)为关键字进行比较
  • 也可以将awk的格式化输出通过管道传递给sort命令,也能实现排序并格式化输出,等价命令为:awk '{printf("%-10s%-10d%-10d%-10d\n",$1,$2,$3,$2*$3)}' file1 | sort -nrk 4

4.2 流程控制

流程控制语句中,if-else用于决策,whilefordo whlie用于循环,breakcontinue用于控制循环

4.2.1 if-else语句

语法结构

{
    if (expression)
    	statements
	else
		statements
}

或者

{if (expression) statements;else statements}    

例八:简单使用if-else语句

[root@CentOS7 commands]# cat file1
Sam	50	8
Jiangle	55	9
Tom	40	6
Tim	60	9

[root@CentOS7 commands]# cat if.awk 
#!/bin/bash
{
	if($2>=50)
		printf("%s has a good salary!\n",$1)	
	else	
		printf("%s need to change a job!\n",$1)
}

[root@CentOS7 commands]# awk -f if.awk file1
Sam has a good salary!
Jiangle has a good salary!
Tom need to change a job!
Tim has a good salary!

说明:

  • awk -f 可以指定文件作为pattern{action},上述例子并未指定pattern
  • 从上述例子可以看出,时薪小于50的,就可以换工作了(hahaa,偶尔皮一下🐶)

4.2.2 while语句

语法结构

{
    while (expression)
    {
    statement1
    statement2
    ...
    }
}

或者

{while (expression){statement1;statement2;...}}

例九:简单的使用while语句

问题描述:

  • data文件中的数按行求和并输出

执行命令:

[root@CentOS7 commands]# cat data 
1 2 3 4
5 6 7 8 9
6 6 6 6 6 6
10 20 30 40 50 

[root@CentOS7 commands]# cat while.awk 
#!/bin/bash
{
	i=1
	sum=0
	while(i<=NF)
	{
		sum+=$i
		i++
	}
	printf("Line %d, sum is %d\n",NR,sum)
}

[root@CentOS7 commands]# awk -f while.awk data
Line 1, sum is 10
Line 2, sum is 35
Line 3, sum is 36
Line 4, sum is 150

说明:

  • 每从输入流读取一行,while循环就会被执行
  • expression的值为真时,进入while循环

4.2.3 for语句

语法结构

{
    for(expresion1;expression2;expression3)
    {
        statement1
        statement2
    }
}

或者

{ for(expresion1;expression2;expression3){statement1;statement2;...}}
  • expression1:进入for循环之前执行一次该语句。一般用于对变量的初始化
  • expression2:每执行一次循环后,都会执行一次该语句,如果结果为真,则继续循环,反之退出循环。一般用于循环的条件判断
  • expression3:每执行一次循环后,都会执行一次该语句。一般用于做变量变化

例十:简单的使用for语句

问题描述:

  • data文件中的数按行求和并输出

执行命令:

[root@CentOS7 commands]# cat data 
1 2 3 4
5 6 7 8 9
6 6 6 6 6 6
10 20 30 40 50 

[root@CentOS7 commands]# cat while.awk 
#!/bin/bash
{
	sum=0
	for(i=1;i<=NF;i++)
		sum+=$i
	printf("Line %d, sum is %d\n",NR,sum)
}

[root@CentOS7 commands]# awk -f for.awk data
Line 1, sum is 10
Line 2, sum is 35
Line 3, sum is 36
Line 4, sum is 150

循环语句里面也可以使用breakcontinue语句,具体的使用这里就不再赘述了。

我的🐴🦆,8k+字!!!第一次总结这么多,累辽~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章