shell编程-awk使用系统学习

awk的基本结构:

awk options ' BEGIN{ print "start" } pattern { commands } END{ print "end" } file

awk语法主要包含三个模块:BEGIN语句块、END语句块和能够使用 模式匹配的通用语句块。这3个部分是可选的,它们中任何一个部分都 可以不出现在脚本中。脚本通常会被包含在单引号或双引号中。

工作原理:

  1. 执行BEGIN { commands } 语句块中的语句。

  2. 从文件或stdin中读取一行,然后执行pattern { commands }。

重复这个过程,直到文件全部被读取完毕。

  1. 当读至输入流(input stream)末尾时,执行END { commands } 语 句块。

BEGIN语句块:

BENGIN语句块是再awk开始从输入流读取行之前被执行,只会执行一次。是可选语句块。

诸如变量初始化、打印输出表格的表头等语句通常都可以写 入BEGIN语句块中

END语句块

与BEGIN语句块类似,只会执行一次,是在awk从输入流读取完所有的行之后立即被执行。也是可选数据库。

像打印所有行的分析结果这类汇总信息,都是 在END语句块中实现的常见任务

Pattern块

pattern语句块用于匹配输入数据的模式。如果省略,则 awk 将对所有行进行操作。

这个语句块同样是可 选的。如果不提供该语句块,则默认执行{ print },即打印每一个读 取到的行。

awk对于读取的每一行,都会执行这个语句块。

每读取一行时,它就会检查该行和提供的样式是否匹配。样式本身可以 是正则表达式、条件以及行匹配范围等。如果当前行匹配该样式,则执 行{ }中的语句。 样式是可选的。如果没有提供样式,那么它就会默认所有的行都是匹配 的,并执行{ }中的语句。

{commands}块

awk脚本中的通用命令,是最重要的块。对与前面模式匹配的进行操作,若是没有pattern则,commands对于读入的每一行执行操作。

options

  • -F <分隔符>--field-separator=<分隔符>: 指定输入字段的分隔符,默认是空格。使用这个选项可以指定不同于默认分隔符的字段分隔符。

  • -v <变量名>=<值>: 设置 awk 内部的变量值。可以使用该选项将外部值传递给 awk 脚本中的变量。

  • -f <脚本文件>: 指定一个包含 awk 脚本的文件。这样可以在文件中编写较大的 awk 脚本,然后通过 -f 选项将其加载。

  • -V--version: 显示 awk 的版本信息。

  • -h--help: 显示 awk 的帮助信息,包括选项和用法示例。

注意点

通常将变量初始化语句(如var=0)以及打印文件头部的 语句放入BEGIN语句块中。若是放在 pattern { commands }语句块中则每行都会被初始化或者打印

awk特殊变量

NR:表示记录数量(number of records),在执行过程中对应 于当前行号。

NF:表示字段数量(number of fields),在执行过程中对应于 当前行的字段数。

$0:这个变量包含执行过程中当前行的文本内容。

$1:这个变量包含第一个字段的文本内容。

$2:这个变量包含第二个字段的文本内容。

$NF:一行中最后一个字段。用print $NF打印一行中最后一个字段,用 $(NF-1)打印 倒数第二个字段

使用例子:

[yuxuanxuan@bastion3 ~]$ echo -e "line1 f2 f3 \nline2 f4 f5 \nline3 f6 f7"|awk '{print "Line_No:"NR,"fields num:"NF,"$0="$0,"$1="$1,"$2="$2,"$3="$NF}'
Line_No:1 fields num:3 $0=line1 f2 f3  $1=line1 $2=f2 $3=f3
Line_No:2 fields num:3 $0=line2 f4 f5  $1=line2 $2=f4 $3=f5
Line_No:3 fields num:3 $0=line3 f6 f7 $1=line3 $2=f6 $3=f7

echo输出三行文本: echo -e "line1 f2 f3 \nline2 f4 f5 \nline3 f6 f7"

awk的pattern部分是{print "Line_No:"NR,"fields num:"NF,"$0="$0,"$1="$1,"$2="$2,"3="NF},对于每行文本都会执行

双引号与单引号的使用

1,awk中print语句中,双引号是被当作拼接使用的:

echo | awk '{ var1="v1"; var2="v2"; var3="v3"; print var1"-"var2"-"var3 ; }'

打印:v1-v2-v3

上面的{}类似一个循环体,对文件中的每一行进行迭代,但是echo只输入一行,所以只打印一次

2,脚本通常被包含在单引号或者双引号中,看具体使用场景而定

例如

[sss@git2 shelltest]$  awk 'BEGIN { i=0 } { i++ } END{ print i}' testfile.txt
5
[sss@git2 shelltest]$  awk "BEGIN { i=0 } { i++ } END{ print i}" testfile.txt
5
[sss@git2 shelltest]$

注意:要是脚本中有awk特殊变量的使用,只能使用单引号

awk -F' +' "{if ($2 > 90){print $1 '\tgood'}else{print $1 '\tbad'} }END{print 'total:',NR}" test.txt

运行报错:

awk: cmd. line:1: {if ( > 90){print '\tgood'}else{print '\tbad'} }END{print 'total:',NR}

awk: cmd. line:1: ^ syntax error

awk: cmd. line:1: {if ( > 90){print '\tgood'}else{print '\tbad'} }END{print 'total:',NR}

awk: cmd. line:1: ^ invalid char ''' in expression

因为其中的双引号中$2会被误认为shell中的变量进行解析,另外'\tgood' '\tbad'也不会被正确解析。需要使用单引号括起,改为如下的形式即可:

awk -F' +' '{if ($2 > 90){print $1 "\tgood"}else{print $1 "\tbad"} }END{print "total:",NR}' test.txt

awk中的if使用

if 语句块

if (表达式 ) {

语句;语句;...

}

属于操作块,if语句若是单个,则不需要{}

awk '{if (condition) {statement1;statement2;statement3;....} }' [input_file]

awk '{if(NR>=2 && NR<=3) print $1}' testfile.txt

选取2,3行打印出来

if else语句块

 awk '{ if (condition) {statement1;statement2;statement3;....} else {statement1;statement2;statement3;....} }' [input_file]

if else-if语句块

if(condition1){

command1

}

else if(condition2) {

command2

}

else if(condition3) {

command3

}

.

.

.

else{

commandN

}

awk的三重运算符

条件为真,conmand1语句块将会执行,条件为假,command2将会执行。

(condition) ? Command1:Command2

例子:

awk '{print ($3 <=20)? "Age less than 20: " $2: "Age over 20: " $2}' students.txt

awk 正则匹配

~,!~表示匹配或者不匹配

// 中是模式。

例如:

第二列匹配正则/th/则执行打印 {print $2,$4}

 awk '$2 ~ /th/ {print $2,$4}' log.txt

log.txt中每一列只要有匹配re的就打印所有行内容

 awk '/re/ ' log.txt

awk for循环的使用

第一种循环体:for (初始化; 条件; 迭代) { # 循环体 }

for (初始化; 条件; 迭代) { # 循环体 }

初始化:初始化一个计数器或变量,通常在循环开始之前执行。

条件:在每次迭代之前检查的条件,如果条件为真,循环会继续执行;如果条件为假,循环会终止。

迭代:在每次迭代之后执行的操作,通常用于递增或递减计数器。

例如,如下例子是依次打印testfile.txt中的每一行的所有字段,NF表示字段数量

awk '{ for(i=1; i<=NF; i++) print $i }' testfile.txt

第二种循环体:for(元素 in 元素列表){#循环体}

比如以下代码:

awk 'BEGIN {
	#awk加注释,跟shell一样,#号开头就可以了。	
	#我们定义一个names的数组,键存的是名字, 值是年龄。
	names["Alice"] = 25
	names["Bob"] = 30
	names["Carol"] = 28
	
	#我们可以循环遍历names数组,并打印元素
	for (name in names) {
		printf("%s的年龄是%d岁\n", name, names[name])
	}
}'

打印

Carol的年龄是28岁

Bob的年龄是30岁

Alice的年龄是25岁

相关推荐
hy____1231 小时前
动态内存管理
linux·运维·算法
龙之叶1 小时前
Android13源码下载和编译过程详解
android·linux·ubuntu
小猪佩奇TONY3 小时前
Linux 内核学习(4) --- devfreq 动态调频框架
linux·运维·学习
爱吃喵的鲤鱼4 小时前
Linux——网络(udp)
linux·网络·udp
千航@abc4 小时前
vim可视化模式的进阶操作
linux·编辑器·vim
小Hier5 小时前
linux系统centos版本上安装mysql5.7
linux·运维·centos
花落已飘5 小时前
RK3568 adb使用
linux·adb·rk3568
龙胖不下锅5 小时前
ubuntu k8s 1.31
linux·ubuntu·kubernetes
张琦-Q6 小时前
ubuntu解决普通用户无法进入root
linux·ubuntu·arm
千航@abc6 小时前
vim的多文件操作
linux·编辑器·vim