awk详解「建议收藏」

2022-09-08 09:38:15 浏览数 (1)

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

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 : %sn", $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

0 人点赞