awk详解「建议收藏」

awk详解「建议收藏」awk是linux中处理文本的强大工具,或者说是一种专门处理字符串的语言,它有自己的编码格式。awk的强大之处还在于能生成强大的格式化报告。awk的命令格式如下:其中常用选项有-F、-f等选项,后面会介绍。例如>awk-F:'{print$1}’file表示把file文件中每行数据以“:”分割后,打印出第一个字段。下面详细介绍使用方式。以下示例如不做…

大家好,又见面了,我是你们的朋友全栈君。

awk是linux中处理文本的强大工具,或者说是一种专门处理字符串的语言,它有自己的编码格式。awk的强大之处还在于能生成强大的格式化报告。
awk的命令格式如下:
这里写图片描述
其中常用选项有 -F、-f等选项,后面会介绍。
例如

>awk -F: '{print $1}' file

表示把file文件中每行数据以“:”分割后,打印出第一个字段。下面详细介绍使用方式。
以下示例如不做说明,均用file文件为例,file文件中数据为:

The dog:There is a big dog and a little dog in the park
The cat:There is a big cat and a little cat in the park
The tiger:There is a big tiger and a litle tiger in the park

一、数据字段变量

awk把分割后的数据字段自动分配给数据字段变量

  • $0表示整行文本
  • $1表示文本行中第一个数据字段
  • $2表示文本行中第二个数据字段
  • $n表示文本行中第n个数据字段
root@lzj-virtual-machine:/home/lzj/demo# awk -F: '{print $2}' file
There is a big dog and a little dog in the park
There is a big cat and a little cat in the park
There is a big tiger and a litle tiger in the park

通过选项-F指定“:”为字段分隔符,把每行数据分为两段,然后输出第二个数据字段$2。

awk  '{print $2}' file

如不显示指定字段分隔符,awk的默认字段分隔符为任意空白字符,包括制表符、空格符、换行符等。

二、在脚本中使用多个命令

上一个示例在program命令脚本中只使用了一个print命令,如果使用多个命令,则在每个命令之间加分号。

root@lzj-virtual-machine:/home/lzj/demo# awk -F: '{$1="Description:"; print $0}' file
Description: There is a big dog and a little dog in the park
Description: There is a big cat and a little cat in the park
Description: There is a big tiger and a litle tiger in the park

用冒号进行分割字段,然后把第一个字段替换为“Description:”,最后打印出整行数据。

三、从文件中读程序命令

如果program程序命令过多,可以单独放在一个文件中,然后从文件中读命令。还是以上面为例,把

{
$1="Description:"
print $0
}

单独放在一个文件script1中。再用awk处理脚本时,需要用选项 -f 指定脚本程序的位置。

root@lzj-virtual-machine:/home/lzj/demo# awk -F: -f script1 file
Description: There is a big dog and a little dog in the park
Description: There is a big cat and a little cat in the park
Description: There is a big tiger and a litle tiger in the park

四、在处理数据之前运行脚本

awk默认每次读入一行数据,然后用脚本进行处理。如果想在处理文本之前预处理一些命令,可以用BEGIN关键字指定。

root@lzj-virtual-machine:/home/lzj/demo# awk -F: 'BEGIN{print "开始处理..."}{print $2}' file
开始处理...
There is a big dog and a little dog in the park
There is a big cat and a little cat in the park
There is a big tiger and a litle tiger in the park

五、在处理数据后运行脚本

用END关键字在处理完所有数据后,再运行善后处理工作。

root@lzj-virtual-machine:/home/lzj/demo# awk -F: '{print $2} END{print "处理结束..."}' file
There is a big dog and a little dog in the park
There is a big cat and a little cat in the park
There is a big tiger and a litle tiger in the park
处理结束...

六、在program中使用变量

变量又分为两种形式:awk内置的变量;用户自定义的变量。
【1】、内置变量
1. 与记录分隔符相关变量
– FS :输入字段分隔符
– OFS:输出字段分隔符
– RS:输入记录分割符
– ORS:输出字段分隔符
– FIELDWIDTHS:定义数据字段的宽度

FS用法

root@lzj-virtual-machine:/home/lzj/demo# awk 'BEGIN{FS=":"} {print $1, $2}' file
The dog There is a big dog and a little dog in the park
The cat There is a big cat and a little cat in the park
The tiger There is a big tiger and a litle tiger in the park

用FS指定字段分隔符为“:”,然后用“:”把每行数据分割为两段。

OFS用法
前面例子没有指定OFS,输出时默认数据字段之间用空格分开。

root@lzj-virtual-machine:/home/lzj/demo# awk 'BEGIN{FS=":"; OFS=">"} {print $1, $2}' file
The dog>There is a big dog and a little dog in the park
The cat>There is a big cat and a little cat in the park
The tiger>There is a big tiger and a litle tiger in the park

用FS指定输入字段分隔符“:”后,每行数据分为两个数据段,输出时,用OFS指定两个数据字段用“>”拼接。

RS和ORS用法
默认情况下RS和ORS设置为“\n”,表示输入数据流中的每一行作为一条记录,输出时每条记录之间也以“\n”进行分割。
下面以file2文件为例,fiel2文件中内容如下:

Tom is a student
and he is 20 years old

Bob is a teacher
and he is 40 years old

默认情况下,每行作为一条记录处理,但此种情况下,要把第一行和第二行作为一条记录处理,第三行和第四行作为一条记录处理。

root@lzj-virtual-machine:/home/lzj/demo# awk 'BEGIN{RS=""; ORS="\n"; FS="and"; OFS=","} {print $1, $2}' file2
Tom is a student
, he is 20 years old
Bob is a teacher
, he is 40 years old

2、与数据分割段有关的变量

ARGC    命令行参数个数
ARGV    命令行参数数组
FILENAME    当前输入文件的名字
IGNORECASE  如果为真,则进行忽略大小写的匹配
ARGIND  当前被处理文件的ARGV标志符
CONVFMT 数字转换格式 %.6g
ENVIRON UNIX环境变量
ERRNO   UNIX系统错误消息
FIELDWIDTHS 输入字段宽度的空白分隔字符串
FNR 文件的当前记录数
NR 已处理的输入记录数
NF 数据文件中数据字段的个数
OFMT    数字的输出格式 %.6g
RSTART  被匹配函数匹配的字符串首
RLENGTH 被匹配函数匹配的字符串长度

下面介绍几个常用的
ARGC和ARGV
ARGC表示命令行中的参数个数,ARGV是参数数组

root@lzj-virtual-machine:/home/lzj/demo# awk -F: '{print ARGC, ARGV[0], ARGV[1]}' file
2 awk file
2 awk file
2 awk file

可见,每处理一行数据时,都是两个参数,第一个是awk本身,第二个是处理的文件名

NF
NF表示数据文件中数据字段的个数,可以通过$NF获取最后一个数据字段

root@lzj-virtual-machine:/home/lzj/demo# awk -F: '{print NF, $NF}' file
2 There is a big dog and a little dog in the park
2 There is a big cat and a little cat in the park
2 There is a big tiger and a litle tiger in the park

每行记录数据通过“:”分割都有两个数据字段。

NR和FNR
FNR表示处理文件的当前记录号,NR表示所有处理文件已处理的输入记录个数。

root@lzj-virtual-machine:/home/lzj/demo# awk -F: '{print "NR="NR, "FNR="FNR, $2}' file file1
NR=1 FNR=1 There is a big dog and a little dog in the park
NR=2 FNR=2 There is a big cat and a little cat in the park
NR=3 FNR=3 There is a big tiger and a litle tiger in the park
NR=4 FNR=1 There is a big dog and a little dog in the forest
NR=5 FNR=2 There is a big cat and a little cat in the forest
NR=6 FNR=3 There is a big tiger and a litle tiger in the forest

注意,不要对NR和FNR加$,例如,如果对NR加$,加入NR等于5,实际就是取每条记录的第5个数据字段,实际没有这么多,只能取到空。

【2】、用户自定义变量
1、在脚本中使用用户自定义变量
建立一个script1的脚本,内容如下:

awk '
BEGIN{
    FS = ":"
    name = "lzj>"
}
{
    $1 = name
    print $0
}' file

运行该脚本 ./script

root@lzj-virtual-machine:/home/lzj/demo# ./script1
lzj> There is a big dog and a little dog in the park
lzj> There is a big cat and a little cat in the park
lzj> There is a big tiger and a litle tiger in the park

在脚本中直接定义了一个name变量,在脚本程序中可以直接引用该变量。注意在shell命令中,赋值语句“=”的前后是不能有空格的,但是在awk程序的内部是可以有的,因为awk是一种单独的编程语言。

2、在命令行中使用变量
首先定义一个script2脚本,其内容为:

BEGIN{
FS = ":"
}
{
    print $n
}

脚本中有一个n的变量,在命令行中传入

root@lzj-virtual-machine:/home/lzj/demo# awk -f script2 n=2 file
There is a big dog and a little dog in the park
There is a big cat and a little cat in the park
There is a big tiger and a litle tiger in the park

注意一个问题:在命令行中传入的参数,默认在BEGIN是不能获取的,例如
script2脚本改为如下,在BEGIN部分获取n的值:

BEGIN{
FS = ":"
print "请输出第二部分...", n
}
{
    print $n
}
root@lzj-virtual-machine:/home/lzj/demo# awk -f script2 n=2 file
请输出第二部分... 
There is a big dog and a little dog in the park
There is a big cat and a little cat in the park
There is a big tiger and a litle tiger in the park

运行命令,发现BEGIN部分的n值并没有打印出来。
但是如果用-v选项指定,并且把变量放在脚本代码之前,在BEGIN部分就可以访问了

root@lzj-virtual-machine:/home/lzj/demo# awk -v n=2 -f script2 file
请输出第二部分... 2
There is a big dog and a little dog in the park
There is a big cat and a little cat in the park
There is a big tiger and a litle tiger in the park

可以看到在BEGIN部分访问到了n的值2

七、在脚本中使用数组

1、数组赋值与查询
awk脚本中的数组有两种使用方式,一种是像其它高级语言一样,用数字下标来索引;另一种是用字典的key值来索引,key必须唯一。
新建script3脚本,内容为:

awk '
BEGIN{ arr["dog"] = "DOG" arr["cat"] = "CAT" print arr["cat"] }' file
root@lzj-virtual-machine:/home/lzj/demo# ./script3 
CAT

2、数组递归
新建脚本script4,内容为:

echo "hello" | awk '
BEGIN{
    arr["a"] = "A"
    arr["b"] = "B"
    arr["c"] = "C"
}
{
    for(var in arr)
    {
        print arr[var]
    }
}'

运行该脚本

root@lzj-virtual-machine:/home/lzj/demo# ./script4 
A
B
C

注意,有时数组的顺序是不一致的。
3、删除数组元素
修改script4脚本,增加delete语句

echo "hello" | awk '
BEGIN{ arr["a"] = "A" arr["b"] = "B" arr["c"] = "C" } { delete arr["c"] for(var in arr) { print arr[var] } }'

运行脚本

root@lzj-virtual-machine:/home/lzj/demo# ./script4 
A
B

可见删除了C元素。

八、脚本中使用正则匹配模式

在脚本中用正则匹配数据行时,正则表达式一定要放在脚本命令的左大括号之前,例如

$awk 'BEGIN{FS = ":"} /dog/{print $2}' file

匹配所有数据行中带dog字符的。

1、用~匹配特定数据字段
用正则表达式匹配指定的数据字段,匹配成功的,就是脚本要处理的数据。

root@lzj-virtual-machine:/home/lzj/demo# awk -F: '$1 ~ /^The cat$/{print $2}' file
There is a big cat and a little cat in the park

数据行中的第一个数据字段满足以The开头,cat结尾的数据行,执行后面的脚本。示例可知只有一条数据行满足记录。

当然也可以通过匹配的否定形式(!~)来排除数据行

root@lzj-virtual-machine:/home/lzj/demo# awk -F: '$1 !~ /dog/{print $2}' file
There is a big cat and a little cat in the park
There is a big tiger and a litle tiger in the park

2、使用数学表达式
可以在匹配数据行时用数学表达式。
以处理file3文件为例,文件内容为:

1:This is 1 line
2:This is 2 line
3:This is 3 line
4:This is 4 line
root@lzj-virtual-machine:/home/lzj/demo# awk -F: '$1 % 2 == 0{print $2}' file3
This is 2 line
This is 4 line

匹配第一个数据字段除2余0的数据行记录。
数学表达式中的+、-、*、/、^(平方)等都可以应用。
另外数学表达式不仅可以用在匹配部分,还可以用在BEGIN、program命令脚本、END部分。
常用的数学比较大小的表达式如下:
这里写图片描述

注意,如果要比较文本的话,只能用“==”进行比较

root@lzj-virtual-machine:/home/lzj/demo# awk -F: '$1 == "The cat"{print $2}' file
There is a big cat and a little cat in the park

九、awk中使用结构化命令

1、if结构
格式为:

if(condition){
    statement1
    statement2
    .....
}else
{
    statement3
    ......  
}

新建script5脚本,如果,每个数据行包括两个数据字段就执行if条件。

awk -F: '{ if(NF == 2) { print $1 print $2 }else { pring NF } }' file

运行脚本

root@lzj-virtual-machine:/home/lzj/demo# ./script5 
The dog
There is a big dog and a little dog in the park
The cat
There is a big cat and a little cat in the park
The tiger
There is a big tiger and a litle tiger in the park

2、while循环结构
格式

while(condition)
{
    statement1
    statement2
    ... 
}

新建script6脚本,计算10以内的奇数和

echo "hello" | awk '
{
    total = 0
    i = 1
    while(i < 10)
    {
        if(i % 2 == 0)
        {
            i++
            continue
        }
        total = total + i
        i++
    }
    print "total=", total
}'

运行脚本

root@lzj-virtual-machine:/home/lzj/demo# ./script6
total= 45

3、for循环
结构

for(variable addignment; condition; iteration peocess)
{
    statement1
    statement2
    ...
}

修改上一示例,改为for循环结构,求10以内奇数的和

echo "hello" | awk '
{
    total = 0
    for(i=1; i<10; i++)
    {
        if(i % 2 == 0)
        {
            continue
        }
        total = total + i
    }
    print "total=", total
}'

结果与上一示例相同。
注意:在awk的for和while循环中也支持breake、continue。

十、awk内置函数

数学函数
这里写图片描述

字符串函数
这里写图片描述

位操作函数
这里写图片描述

时间函数
这里写图片描述

十一、用户自定义函数

用户自定义函数一定要放在调用之前进行定义
格式

function function_name([variable])
{ statement1 statement2 .... }

例如处理file4文件,内容如下,只提取其中姓名和电话

Bob NanjingRoad 6623432
Terry BeijingRoad 6689764
Lily GuangzRoad 6623678

新建脚本script7,内容如下

awk '
function fshow() 
{
    printf "%-5s : %s\n", $1, $3
}
BEGIN{
    print "开始处理..."
}
{
    fshow() 
}' file4

运行脚本如下

root@lzj-virtual-machine:/home/lzj/demo# ./script7 
开始处理...
Bob   : 6623432
Terry : 6689764
Lily  : 6623678

注意:
printf的用法通C语言一样;
在脚本中BEGIN后面一定要紧跟“{”,否则会出错。

参考:linux脚本教程宝典

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/157379.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • JAVA中运算符的详讲

    JAVA中运算符的详讲

  • 什么是友元类[通俗易懂]

    什么是友元类[通俗易懂]======================什么是友元类=======================     当一个类B成为了另外一个类A的“朋友”时,那么类A的私有和保护的数据成员就可以被类B访问。我们就把类B叫做类A的友元。=======================友元类能做什么=======================     友元类可以通过自己的方法来

  • 机器学习框架简述

    机器学习框架简述机器学习框架意味着一个能够整合包括机器学习算法在内的所有机器学习的系统或方法,使用户最有效的使用它们。具体来讲,这包括数据表示与处理的方法、表示和建立预测模型的方法、评价和使用建模结果的方法。在所有可用的机器学习框架中,着重于迭代算法和交互处理的框架被公认为是最好的,因为这些特性可以促进复杂预测模型估计和研究人员与数据间的良好交互。当下,优秀的机器学习框架依旧需要包含大数据功能…

  • sql中ddl和dml(数据库表与视图的区别)

    DDL和DML的定义和区别1、DML(DataManipulationLanguage)数据操纵语言:适用范围:对数据库中的数据进行一些简单操作,如insert,delete,update,select等.对表(索引和序列)中数据操作就是DML,对数据库中的(表,索引,序列,同义词等)都是DDL操作 2、DDL(DataDefinitionLanguage)数据定义语言:适用范围:对数据库…

  • 原生js动态添加元素

    原生js动态添加元素<!DOCTYPEhtml><htmllang=”en”><head><metacharset=”UTF-8″><metaname=”viewport”content=”width=device-width,initial-scale=1.0″><title>原生js动态添加元素</title><style>.phone{.

  • UIScrollView 与 touchesBegan 冲突解决方法

    UIScrollView 与 touchesBegan 冲突解决方法UIScrollView与touchesBegan冲突解决方法

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号