前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >awk详解「建议收藏」

awk详解「建议收藏」

作者头像
全栈程序员站长
发布2022-09-08 09:38:15
1.8K0
发布2022-09-08 09:38:15
举报
文章被收录于专栏:全栈程序员必看

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

awk是linux中处理文本的强大工具,或者说是一种专门处理字符串的语言,它有自己的编码格式。awk的强大之处还在于能生成强大的格式化报告。 awk的命令格式如下:

其中常用选项有 -F、-f等选项,后面会介绍。 例如

代码语言:javascript
复制
>awk -F: '{print $1}' file

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

代码语言:javascript
复制
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个数据字段
代码语言:javascript
复制
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。

代码语言:javascript
复制
awk  '{print $2}' file

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

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

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

代码语言:javascript
复制
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程序命令过多,可以单独放在一个文件中,然后从文件中读命令。还是以上面为例,把

代码语言:javascript
复制
{
$1="Description:"
print $0
}

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

代码语言:javascript
复制
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关键字指定。

代码语言:javascript
复制
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关键字在处理完所有数据后,再运行善后处理工作。

代码语言:javascript
复制
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用法

代码语言:javascript
复制
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,输出时默认数据字段之间用空格分开。

代码语言:javascript
复制
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文件中内容如下:

代码语言:javascript
复制
Tom is a student
and he is 20 years old

Bob is a teacher
and he is 40 years old

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

代码语言:javascript
复制
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、与数据分割段有关的变量

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

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

代码语言:javascript
复制
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获取最后一个数据字段

代码语言:javascript
复制
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表示所有处理文件已处理的输入记录个数。

代码语言:javascript
复制
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的脚本,内容如下:

代码语言:javascript
复制
awk '
BEGIN{
    FS = ":"
    name = "lzj>"
}
{
    $1 = name
    print $0
}' file

运行该脚本 ./script

代码语言:javascript
复制
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脚本,其内容为:

代码语言:javascript
复制
BEGIN{
FS = ":"
}
{
    print $n
}

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

代码语言:javascript
复制
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的值:

代码语言:javascript
复制
BEGIN{
FS = ":"
print "请输出第二部分...", n
}
{
    print $n
}
代码语言:javascript
复制
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部分就可以访问了

代码语言:javascript
复制
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脚本,内容为:

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

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

代码语言:javascript
复制
echo "hello" | awk '
BEGIN{
    arr["a"] = "A"
    arr["b"] = "B"
    arr["c"] = "C"
}
{
    for(var in arr)
    {
        print arr[var]
    }
}'

运行该脚本

代码语言:javascript
复制
root@lzj-virtual-machine:/home/lzj/demo# ./script4 
A
B
C

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

代码语言:javascript
复制
echo "hello" | awk '
BEGIN{ arr["a"] = "A" arr["b"] = "B" arr["c"] = "C" } { delete arr["c"] for(var in arr) { print arr[var] } }'

运行脚本

代码语言:javascript
复制
root@lzj-virtual-machine:/home/lzj/demo# ./script4 
A
B

可见删除了C元素。

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

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

代码语言:javascript
复制
$awk 'BEGIN{FS = ":"} /dog/{print $2}' file

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

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

代码语言:javascript
复制
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结尾的数据行,执行后面的脚本。示例可知只有一条数据行满足记录。

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

代码语言:javascript
复制
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文件为例,文件内容为:

代码语言:javascript
复制
1:This is 1 line
2:This is 2 line
3:This is 3 line
4:This is 4 line
代码语言:javascript
复制
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部分。 常用的数学比较大小的表达式如下:

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

代码语言:javascript
复制
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结构 格式为:

代码语言:javascript
复制
if(condition){
    statement1
    statement2
    .....
}else
{
    statement3
    ......  
}

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

代码语言:javascript
复制
awk -F: '{ if(NF == 2) { print $1 print $2 }else { pring NF } }' file

运行脚本

代码语言:javascript
复制
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循环结构 格式

代码语言:javascript
复制
while(condition)
{
    statement1
    statement2
    ... 
}

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

代码语言:javascript
复制
echo "hello" | awk '
{
    total = 0
    i = 1
    while(i < 10)
    {
        if(i % 2 == 0)
        {
            i++
            continue
        }
        total = total + i
        i++
    }
    print "total=", total
}'

运行脚本

代码语言:javascript
复制
root@lzj-virtual-machine:/home/lzj/demo# ./script6
total= 45

3、for循环 结构

代码语言:javascript
复制
for(variable addignment; condition; iteration peocess)
{
    statement1
    statement2
    ...
}

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

代码语言:javascript
复制
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内置函数

数学函数

字符串函数

位操作函数

时间函数

十一、用户自定义函数

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

代码语言:javascript
复制
function function_name([variable])
{ statement1 statement2 .... }

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

代码语言:javascript
复制
Bob NanjingRoad 6623432
Terry BeijingRoad 6689764
Lily GuangzRoad 6623678

新建脚本script7,内容如下

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

运行脚本如下

代码语言:javascript
复制
root@lzj-virtual-machine:/home/lzj/demo# ./script7 
开始处理...
Bob   : 6623432
Terry : 6689764
Lily  : 6623678

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

参考:linux脚本教程宝典

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、数据字段变量
  • 二、在脚本中使用多个命令
  • 三、从文件中读程序命令
  • 四、在处理数据之前运行脚本
  • 五、在处理数据后运行脚本
  • 六、在program中使用变量
  • 七、在脚本中使用数组
  • 八、脚本中使用正则匹配模式
  • 九、awk中使用结构化命令
  • 十、awk内置函数
  • 十一、用户自定义函数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档