首页 > 系统相关 >SHELL脚本学习(十四)gawk进阶

SHELL脚本学习(十四)gawk进阶

时间:2024-07-01 21:58:53浏览次数:20  
标签:arr SHELL 进阶 BEGIN gawk cat print 变量

一、使用变量

gawk支持两种变量

  • 内建变量
  • 自定义变量
1.1 内建变量
1.1.1 字段和记录分隔符变量

数据字段变量允许使用美元符号 $ 和 位置来引用对应的字段。 $1 对应第一个数据字段,$2对应第二个数据字段,以此类推。

数据字段用字段分隔符划定。默认情况下,字段分隔符是一个空白字符(空格或制表符)。可以通过 -F选项修改字段分隔符。也可以使用特殊的内建变量FS修改字段分隔符。

有一组内建变量可以控制输入和输出数据中字段和记录的处理方式:

gawk数据字段和记录变量

变 量描 述
FIELDWIDTHS由空格分隔的一串数字,定义了每个数据字段的确切宽度
FS输入字段分隔符
RS输入记录分隔符
OFS输出字段分隔符
ORS输出记录分隔符
$ cat < data1
header line
data line 1
End of data line

#默认情况
$ gawk '{print $1,$2}' data1
header line
data line
End of

#1、OFS测试

$ gawk 'BEGIN{OFS="|-|"}
{print $1,$2}' data1
header|-|line
data|-|line
End|-|of

#2、ORS测试

$ gawk 'BEGIN{ORS="|-|"}
{print $1,$2}
END{print "\n"}' data1 
header line|-|data line|-|End of|-|

默认输出字段分隔符是空格,第1个例子将输出字段分隔符换成了"|-|“。
默认输出记录分隔符是换行,第2个例子将输出记录分隔符换成了”|-|"。

FIELDWIDTHS会根据提前设置好的字段宽度来划分字段。

下面这个例子将固定格式的时间划分成 年、月、日、时、分

$ cat <data2
202401011015
202402020900
202403030130

$ gawk 'BEGIN{
FIELDWIDTHS="4 2 2 2 2 2"}
{print $1,$2,$3,$4,$5}' data2
2024 01 01 10 15 
2024 02 02 09 00 
2024 03 03 01 30 

FS默认为空白符,RS默认为换行符。也就是说gawk默认一行为一条记录。但有时一行数据是一个字段,多行数据组成一条记录。这时可以将FS设置成\n,将RS设置成空字符串。

$ cat <data3
zhangsan
17
haerbin

lisi
20
beijing

$ gawk 'BEGIN{FS="\n";RS=""}
{print"name:"$1,"age:"$2,"city:"$3}' data3
name:zhangsan age:17 city:haerbin
name:lisi age:20 city:beijing

1.1.2 数据变量

除了字段和记录分隔符变量外,gawk还提供了其他一些变量帮助了解数据的变化。

更多的gawk内建变量

变量描述
ARGC命令行参数的数量
ARGIND当前处理的文件在ARGV中的索引
ARGV包含命令行参数的数组
CONVFMT数字的转换格式(参见printf语句),默认为%.6g
ENVIRON当前环境变量及其值组成的关联数组
ERRNO当读取或关闭输入文件发生错误时的系统错误号
FILENAME用作gawk输入的数据文件的名称
FNR当前数据文件中已处理的记录数
IGNORECASE非0表示忽略大小写
NF数据文件中的字段总数
NR已处理的输入记录数
OFMT数字的输出格式。默认值为%.6g。以浮点数或科学计数法表示,以较短者为准,最多是使用6位小数
RLENGTH由match函数所匹配的子串长度
RSTART由match函数所匹配的子串的起始位置

下面测试几个常用的变量

#ARGC:命令行参数的数量
#ARGV:当前处理的文件在ARGV中的索引
$ gawk 'BEGIN{print ARGC,ARGV[0],ARGV[1],ARGV[2]}' data1 data2
3 gawk data1 data2

#ENVIRON:当前环境变量及其值组成的关联数组
$ gawk 'BEGIN{print ENVIRON["HOME"]}' 
/home/ubuntu

#FILENAME :用作gawk输入的数据文件的名称
$ gawk 'END{print FILENAME}' data1
data1
$ cat < data1
header line
data line 1
End of data line

$ cat <data2
202401011015
202402020900
202403030130

#NR:已处理的输入记录数
#FNR:当前数据文件中已处理的记录数
#NF:数据文件中的字段总数
#$NF:最后一个字段的值
$ gawk '{print "NR="NR,"FNR="FNR,"NF="NF,"$NF="$NF}' data1 data2
NR=1 FNR=1 NF=2 $NF=line
NR=2 FNR=2 NF=3 $NF=1
NR=3 FNR=3 NF=4 $NF=line
NR=4 FNR=1 NF=1 $NF=202401011015
NR=5 FNR=2 NF=1 $NF=202402020900
NR=6 FNR=3 NF=1 $NF=202403030130
NR=7 FNR=4 NF=0 $NF=

1.2 自定义变量

gawk的自定义变量由任意个字母、数字和下划线组成,但不能以数字开头。
gawk自定义变量区分大小写。

1.2.1 在脚本中为变量赋值
$ gawk 'BEGIN{test="this is a test.";print test}'
this is a test.

$ gawk 'BEGIN{test=100;print test*(test-1)}'
9900

$ gawk 'BEGIN{test=100;print test^2}'
10000
1.2.2 在命令行中给变量赋值
$ cat <data1
header line
data line 1
End of data line

$ gawk '{print $field}'  field=1 data1
header
data
End

$ gawk '{print $field}'  field=2 data1
line
line
of

这个例子通过在命令行中给变量赋值,可以显示不同的字段。
这个特性可以在不改变脚本代码的情况下改变脚本的行为。

使用命令行参数定义变量有一个问题:设置变量后,这个变量在BEGIN模块不可用
如下:

$ gawk 'BEGIN {print "field="field}' field=3 data1
field=

可以用 -v选项解决这个问题。-v选项允许在BEGIN之前定义变量。

$ gawk -v field=3 'BEGIN {print "field="field}' field=3 data1
field=3
二、处理数组

数组用于单个变量存储多个值,gawk语言使用关联数组提供数组功能。类似c++中的unorder_map。

2.1 定义数组变量

可以用赋值语句定义数组变量。格式如下;

var[index]=element
var:数组变量名
index:索引
element:索引对应的值

$ gawk 'BEGIN{arr["name"]="lilei";arr["age"]=20;
print arr["name"],arr["age"]}'
lilei 20
2.2 遍历数组变量

格式:

for index in array
{
 statement
}

for语句每次循环时会把下一个数组元素的索引赋值给index。

$ gawk 'BEGIN{arr["name"]="lilei";arr["age"]=20;
for (ind in arr)
{
print "arr["ind"]="arr[ind]
}}'
arr[age]=20
arr[name]=lilei

索引没有固定的返回顺序。

2.3 删除数组变量

从关联数组中删除数据需要使用 delete 命令;

delete array[index]

下面使用delete命令的例子

$ cat < gawk_cmd
BEGIN {
    arr["name"]="lilei";
    arr["age"]=20;
    arr["city"]="haerbin";
    for (ind in arr)
    {
        print "arr["ind"] :" arr[ind];
    }
    delete arr["age"];
    print "---------"
    for (ind in arr)
    {
        print "arr["ind"] :" arr[ind];
    }
}

$ gawk -f gawk_cmd
arr[age] :20
arr[city] :haerbin
arr[name] :lilei
---------
arr[city] :haerbin
arr[name] :lilei

每行代码后面的分号 ( ; ) 写不写都行。

三、 使用模式
3.1 正则表达式

sed 只支持基础正则表达式(BRE),gawk支持基础正则表达式(BRE) 和扩展正则表达式(ERE)。

下面的第1个例子输出张三的年龄,第2个例子输出年龄在20~30之间的人的名字。

$ cat <data3
zhangsan
17
haerbin

lisi
20
beijing

$ gawk 'BEGIN{FS="\n";RS=""}
/zhangsan/{print $2}' data3
17

$ gawk 'BEGIN{FS="\n";RS=""}
/2./{print $1}' data3
lisi
3.2 匹配操作符

匹配操作符 (~) 使用格式:

数据字段 ~ /正则表达式/

和上面的例子相同,下面第1个例子输出zhangsan的年龄,第2个例子输出年龄在20~30之间的人的名字。


$ gawk 'BEGIN{FS="\n";RS=""}
$1 ~ /zhangsan/{print $1,$2,$3}' data3
zhangsan 17 haerbin

$ gawk 'BEGIN{FS="\n";RS=""}
$2 ~ /^2.$/{print $1,$2,$3}' data3
lisi 20 beijing

3.3 数学表达式

处理正则表达式,gawk还可以在匹配模式中使用数学表达式。
可以使用任何常见的数学表达式:

操作符描述
==等于
<=小于等于
<小于
>大于
>=大于等于

还是相同的例子,输出张三的年龄

$ cat <data3
zhangsan
17
haerbin

lisi
20
beijing

$ gawk 'BEGIN{FS="\n";RS=""}
$1=="zhangsan"{print "age="$2}' data3
age=17

四、结构化命令

gawk 中的结构化命令和 c语言 中的分支和循环结构基本一致。

4.1 if语句

输出年龄是否大于18岁

$ cat <data3
zhangsan
17
haerbin

lisi
20
beijing


$ cat < gawk_cmd
BEGIN {
   FS="\n"
   RS=""
   print "Begin"
}

{
    cmp=""
    age=18
    if ($2 <= age)
    {
        cmp=" less than "
    }
    else
    {
        cmp=" greater than "
    }
    print $1 cmp,age
}

END{
    print "End of file"
}


$ gawk -f gawk_cmd data3
Begin
zhangsan less than  18
lisi greater than  18
End of file

4.2 while 语句

格式:

while (condition)
{
 statements
}

下面例子输出某次跳远比赛各个选手的平均成绩。

$ cat < data1
5.5 6.5 7.5
6.6 6.5 6.5
6.6 7.5 5.9

$ cat < gawk_cmd
BEGIN {
   print "Begin"
}

{
    i=1
    sum=0.0
    while (i <= NF)
    {
        sum+=$i
        i++
    }
    print sum/NF
}

END{
    print "End of file"
}

$ gawk -f gawk_cmd data1
Begin
6.5
6.53333
6.66667
End of file
4.3 do-while语句

格式:

do
{
 statements
}
while (condition)

do-whilewhile 唯一区别是 do-while保证statements会在条件被求值之前至少执行一次。

4.4 for语句

格式:

for (变量赋值; condition; 迭代处理)
{
 statements
}

下面使用for语句计算跳远比赛的平均成绩。

$ cat < gawk_cmd
BEGIN {
   print "Begin"
}

{
    sum=0.0
    for(i=1;i<=NF;i++)
    {
        sum+=$i
    }
   
    print sum/NF
}

END{
    print "End of file"
}

$ gawk -f gawk_cmd data1
Begin
6.5
6.53333
6.66667
End of file
五、格式化打印
5.1 printf 命令

gawk中的printf命令和 C语言 中的printf函数一样。
格式:

printf “format string”,var1,var2…

格式说明符的控制字母

控制字母描述
c数字作为ASCII字符显示
d和i显示整数值
e用科学计数法显示数字
f显示浮点数
g用科学计数法或浮点数显示(较短的格式有限)
o显示八进制
s显示字符串
x显示十六进制
X显示十六进制,但用大写字母A-F
#将输入数据当做字符串
$ echo "200.33333"| gawk '{printf "%s\n",$1}'
200.33333

#将输入数据当作小数并保留两位小数
$ echo "200.33333"| gawk '{printf "%2.2f\n",$1}'
200.33

#将输入数据当作整数,并且至少输出5位,不足5位向前补0
$ echo "200.33333"| gawk '{printf "%05d\n",$1}'
00200
六、自定义函数
6.1 定义函数

格式:

function name ([variables])
{
  statements
}

6.2 使用函数

使用自定义函数计算平均成绩

$ cat < gawk_cmd
function average(s1,s2,s3)
{
    return (s1 + s2 + s3)/3
}

BEGIN {
   print "Begin"
   
}

{
    printf "average scores:%.2f\n",average($1,$2,$3)
}

END{
    print "End of file"
}


$ gawk -f gawk_cmd data1
Begin
average scores:6.50
average scores:6.53
average scores:6.67
End of file
6.3 函数库

也可以把常用的函数放到一个文件中,封装成函数库。

$ cat < lib_func
function average(s1,s2,s3)
{
    return (s1 + s2 + s3)/3
}

$ cat < lib_func
function average(s1,s2,s3)
{
    return (s1 + s2 + s3)/3
}
ubuntu@VM-8-14-ubuntu:~$ cat < gawk_cmd

BEGIN {
   print "Begin"
}

{
    printf "average scores:%.2f\n",average($1,$2,$3)
}

END{
    print "End of file"
}

$ gawk -f lib_func -f gawk_cmd  data1
Begin
average scores:6.50
average scores:6.53
average scores:6.67
End of file

标签:arr,SHELL,进阶,BEGIN,gawk,cat,print,变量
From: https://blog.csdn.net/weixin_37703001/article/details/140106872

相关文章

  • Python进阶教程--科学计算基础软件包NumPy
    NumPy(NumericalPython)是一个开源的Python库,用于科学计算。它提供了一个高性能的多维数组对象和用于处理这些数组的工具。NumPy是Python科学计算的基础库,被广泛用于数据分析、机器学习、科学计算等领域。1.1NumPy概述NumPy是Python的一个扩展库,主要用于处理大型多维数组......
  • JavaScript 进阶之旅:Symbol 引领标识符新纪元
    个人主页:学习前端的小z个人专栏:JavaScript精粹本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结,欢迎大家在评论区交流讨论!文章目录......
  • Java进阶学习|Day4.Java多线程,线程池
    文章目录了解多线程CPU进程(Process)线程多线程开发多线程优点实现方式继承Thread类实现Runnable接口实现Callable接口线程状态转换线程状态线程调度调整线程优先级线程睡眠线程等待线程让步线程加入线程唤醒线程同步线程同步方式多线程间通信线程池了解线程池定义......
  • JINGWHALE 数字认证体系 · 进阶知识库
    JINGWHALE数字认证体系是JINGWHALE数字科学艺术创新中心的数字认证服务。◢◤宗旨致力于数字化知行合一的知识赋能!◥数字化人才培养培养数字化思维,传播数字化知识,赋能各行业数字化。◥职业人才发展无缝衔接学校高等教育与企业职业工作(学校高等教育<->J......
  • 机器翻译及实践 进阶版:基于Transformer实现机器翻译(日译中)
    机器翻译及实践进阶版:基于Transformer实现机器翻译(日译中)前言一、所需要的前置知识——Transformer1.自注意力机制1.1Query&Key&Value版注意力机制1.1.1什么是Query&Key&Value版注意力机制1.1.2为什么引入Query&Key&Value版注意力机制1.1.3如何实现Query&Key&Value......
  • 一键进阶ComfyUI!懂AI的设计师现在都在用的节点式Stable Diffusion!内附安装包
    大家好,我是设计师阿威目前使用StableDiffusion进行创作的工具主要有两个:WebUI和ComfyUI。而更晚出现的ComfyUI凭借超高的可定制性和复现性迅速火遍全球。有设计师表示SD发布了XL1.0后,ComfyUI用它优秀的底层逻辑率先打击了臃肿不稳定的WebUI1.6,成为更适合“体验”XL的......
  • 写个时钟(进阶篇)
    在“写个时钟(行为篇)”中,我们通过 JavaScript 动态创建的时针、分针和秒针,并直接在 JavaScript 中通过控制行内样式的 transform属性,设置 rotate 的值,实现指针的旋转。这样的方式,对于 DOM 的控制消耗较大,若放到大项目中,对项目性能具有一定的影响,也让 JavaScript 代......
  • 【动画进阶】类 ChatGpt 多行文本打字效果
    今天我们来学习一个有意思的多行文本输入打字效果,像是这样:这个效果其实本身并非特别困难,实现的方式也很多,在本文中,我们更多的会聚焦于整个多行打字效果最后的动态光标的实现。也就是如何在文本不断变长,在不确定行数的情况下,让文字的最末行右侧处,一直有一个不断闪烁的光标效果:......
  • 使用PowerShell执行的命令和示例,用于增强Windows系统的安全性巡检项目:2024
    使用PowerShell执行的命令和示例,用于增强Windows系统的安全性巡检项目:检查系统服务和进程:powershellCopyCode#列出所有正在运行的服务Get-Service|Where-Object{$_.Status-eq'Running'}#列出所有正在运行的进程Get-Process检查本地安全策略和组策略:powersh......
  • shell之条件测试语句
    shell之条件测试语句目录shell之条件测试语句一、test命令或[]中括号判断1、test命令2、[]中括号2.1整数值比较[]2.2实例操作2.2.1查看系统内存是否超出预定值2.2.2比较两个数的大小2.3字符串比较2.3.1案例:判断字符串是否相同2.3.2案例:判断字符串是否为空2.4逻辑测试(短......