awk命令笔记

awk 'BEGIN { commands } PATTERN { commands } END { commands }'
     begin块               body块                 end块
  1. begin/end区分大小写,大写有效。
  2. 空格可选。
  3. 内置变量需大写。

执行流程:
1)先执行begin块。
相当于循环初始化。
2)对每条输入记录,执行body块。
相当于执行循环体。
如果是处理多行文本,默认用换行符拆分记录,即循环每行进行处理。
3)对每条记录(每行文本)的默认处理:
用分隔符(默认是空格)分隔每行中的字段,分别赋值给$1, $2 … ($0代表整行)
根据需要对各个字段进行处理,输出等。
4)循环结束后,执行end块。

pattern模式:
1)/正则表达式/:/some string/
2)关系表达式:$2>10 NR%2==0
3)模式匹配表达式: ~ ~!
4)范围区间:
'NR==1, NR==10' 1-10行

$ cat /tmp/test.log 
2023-05-18 05:08:56.965846   460  4936 I SOMEIP  : 2023-05-18 05:08:56.871641 [info] [TID:571]  repetitionsBaseDelay_ = 100
2023-05-18 05:08:56.965863   460  4936 I SOMEIP  : 2023-05-18 05:08:56.871645 [info] [TID:571]  repetitionsMax_ = 3
2023-05-18 05:08:30.896556  1538  1538 I SettingsIFImpl: line 1
2023-05-18 05:08:30.896556  1538  1538 I SettingsIFImpl: line 2

# 包含SOMEIP的行
$ awk '/SOMEIP/' /tmp/test.log
2023-05-18 05:08:56.965846   460  4936 I SOMEIP  : 2023-05-18 05:08:56.871641 [info] [TID:571]  repetitionsBaseDelay_ = 100
2023-05-18 05:08:56.965863   460  4936 I SOMEIP  : 2023-05-18 05:08:56.871645 [info] [TID:571]  repetitionsMax_ = 3

# 不包含SOMEIP的行
$ awk '!/SOMEIP/' /tmp/test.log
2023-05-18 05:08:30.896556  1538  1538 I SettingsIFImpl: line 1
2023-05-18 05:08:30.896556  1538  1538 I SettingsIFImpl: line 2

# 把字段$6匹配模式的行,打印每行中$6后续内容
$ awk 'BEGIN{ ORS=" " } $6~/SOMEIP/{ for(i=8; i<=NF; i++) { print $i } print "\n" }' /tmp/test.log
2023-05-18 05:08:56.871641 [info] [TID:571]  repetitionsBaseDelay_ = 100 
 2023-05-18 05:08:56.871645 [info] [TID:571]  repetitionsMax_ = 3 
 2023-05-18 05:08:56.871641 [info] [TID:571]  repetitionsBaseDelay_ = 100 
 2023-05-18 05:08:56.871645 [info] [TID:571]  repetitionsMax_ = 3 

内置变量

FILENAME: 当前文件名
NR: 表示所有处理文件已处理的输入记录个数
FNR: 文件的当前记录数
NF: 表示数据文件中数据字段的个数,可以通过$NF获取最后一个数据字段
ARGC: 命令行参数个数
ARGV: 命令行参数数组
$0: 这个变量包含执行过程中当前行的文本内容。
$n: 一行记录的第n个字段,例如$1, $2

FS:输入字段分隔符
OFS:输出字段分隔符
RS:输入记录分割符
ORS:输出字段分隔符
FIELDWIDTHS:定义数据字段的宽度
$ awk '{print FILENAME, NF, $0}' /tmp/test.log 
/tmp/test.log 8 2023-05-18 05:08:30.896556  1538  1538 I SettingsIFImpl: line 1
/tmp/test.log 8 2023-05-18 05:08:30.896556  1538  1538 I SettingsIFImpl: line 2

$ awk '{print FILENAME "line>>" NR, $0}' /tmp/test.log 
/tmp/test.logline>>1 2023-05-18 05:08:30.896556  1538  1538 I SettingsIFImpl: line 1
/tmp/test.logline>>2 2023-05-18 05:08:30.896556  1538  1538 I SettingsIFImpl: line 2

body块:

/pattern/ { commands }

1)匹配正则表达式pattern的记录,执行命令commands。
2)可以有多个匹配模式,例如:
(1)当匹配pattern1时,执行commands1。如果匹配pattern2就执行commands2.
(2)next作用就是跳过后面的模式匹配和命令(类似if/else的关系);如果没有next命令,则每个模式匹配都会进行判断。

/patten1/ {commands1; next} /pattern2/ {commands2}

3)如果省略{commands},默认执行print $0。只执行/pattern/匹配过滤。
(1)对于简单字符串,退化成grep。
(2)利用内置变量和表达式做复杂查找(筛选),例如筛选出偶数行。

$ awk '/Max/' /tmp/test.log 
$ awk 'NR%2==0' /tmp/test.log

4)print函数在commands中可以重定向输出到文件或者管道

awk 'NR%2==0 { print $1 > "/tmp/part.log" }' /tmp/test.log

各个命令块:
1)可编写多条语句。每行一个命令,结尾不必有分号。也可以分号分隔的多条命令。
2)支持if-else,for,while等控制结构。
3)支持数据,索引可用数字或字符串,相当于map。
4)可自定义函数
function find_min(num1, num2) { if (num1 < num2) return num1 return num2 }
5)内置函数:
(1)数学函数:sin, cos, log, sqrt, int, rand
(2)字符串函数:gsub, sub, substr, index, length, match, split, tolower, toupper, sprintf, strtonum
sub(reg, str [, target])
a) 匹配reg的字符串,替换为str。
b) target为替换目标字符串,默认为 0 ,可指定为某个表里或者字段 0,可指定为某个表里或者字段 0,可指定为某个表里或者字段n。
c) gsub和sub原型一样,替换所有匹配reg的字符串,sub只替换第一个出现。
gensub(reg, str, h [, target])
a) h可指定替换第几个出现的reg,或者“g/G”标识替换全部。
b) 在str中可以通过“\n”引用reg出现的位置。
print
(3)时间函数:mktime, strftime, systime
(4)位操作函数:and, or, xor, compl, lshift, rshift
(5)其他函数:close, flush, exit, delete, getline, next, nextfile, return system

# sub,gsub例子
# sub
$ cat /tmp/test.log 
2023-05-18 05:08:56.965846   460  4936 I SOMEIP  : 2023-05-18 05:08:56.871641 [info] [TID:571] client_timer_18215_1 repetitionsBaseDelay_ = 100
2023-05-18 05:08:56.965863   460  4936 I SOMEIP  : 2023-05-18 05:08:56.871645 [info] [TID:571] client_timer_18215_1 repetitionsMax_ = 3

#sub函数只替换第一次出现的字符串
$ awk '{ sub(/2023-05-18/, "1234-56-78"); print $0 }' /tmp/test.log 
1234-56-78 05:08:56.965846   460  4936 I SOMEIP  : 2023-05-18 05:08:56.871641 [info] [TID:571] client_timer_18215_1 repetitionsBaseDelay_ = 100
1234-56-78 05:08:56.965863   460  4936 I SOMEIP  : 2023-05-18 05:08:56.871645 [info] [TID:571] client_timer_18215_1 repetitionsMax_ = 3

#gsub函数替换一行中所有匹配的字符串
$ awk '{ gsub(/2023-05-18/, "1234-56-78"); print $0 }' /tmp/test.log 
1234-56-78 05:08:56.965846   460  4936 I SOMEIP  : 1234-56-78 05:08:56.871641 [info] [TID:571] client_timer_18215_1 repetitionsBaseDelay_ = 100
1234-56-78 05:08:56.965863   460  4936 I SOMEIP  : 1234-56-78 05:08:56.871645 [info] [TID:571] client_timer_18215_1 repetitionsMax_ = 3

# gsub删除收尾空格
$ awk '{gsub(/^ +| +$/,"")} {print "=" $0 "="}' onefile.txt

用多个分隔符拆分记录:

$ cat test.log
2023-05-18 05:08:56.965846   460  4936 I SOMEIP

# 用空格、.、:多个分隔符来拆分记录,默认只用空格分隔符
$ awk -F "[ .:]" '{print $1,$2,$3,$4,$5}' test.log 
2023-05-18 05 08 56 965846

# FS和-F参数等效
$ awk 'BEGIN{FS="[ .:]"} {print $1,$2,$3,$4,$5}' test.log 
2023-05-18 05 08 56 965846

自定义变量
1)对脚本比较有用,命令行中用处不大。
2)在命令行中,自定义变量写在脚本指令之后。脚本指令紧挨着awk。

$ awk '{ print name"="age }' name=tom age=12 /tmp/test.log 
tom=12
tom=12

数组:
1)关联数组,map类型。
2)不用先定义
3)for…in循环可能无序,for (i=1…)循环有序

$ awk '
BEGIN {
str="this is a string"; 
len=split(str, array, " "); 
print length(array), len; 
for (i in array) 
	print i": "array[i]; 
}'

4 4
1: this
2: is
3: a
4: string

$ awk 
'BEGIN {
str="this is a string"; 
len=split(str, array, " "); 
print length(array), len; 
for (i=1; i<=len; i++) 
	print i": "array[i]; 
}'
4 4
1: this
2: is
3: a
4: string

$ awk 
'BEGIN{ 
arr["one"]=1; 
arr["two"]=2; 
arr["three"]=3; 

for (item in arr) 
	print item"->"arr[item] 
}'
three->3
two->2
one->1

流程控制:

$ cat /tmp/file.txt 
line 1
line 2
line 3
line 4
line 5
line 6

# if
$ awk '{ 
if (NR % 2 == 0) 
{
	print $0
} 
else if (NR %3 == 0) 
{
	print $0
} 
}' /tmp/file.txt 

line 2
line 3
line 4
line 6

# while 循环
$ awk 'BEGIN{ 
count=3; 
while (count>0) 
{
	print count; 
	count--;
} 
}' /tmp/file.txt 
3
2
1

# for循环
$ awk 'BEGIN{ 
for(count=3; count>0; count--) 
{
	print count;
} 
}' /tmp/file.txt 
3
2
1

控制命令:

break,退出while/for循环
continue,继续下一次循环
next,继续系一条记录,把body块作为循环体,next类似continue,跳到下一条记录。
exit, 在body块中exit,结束body块循环,执行END;在END中exit,退出程序。包body块作为循环体,exit类似break。

数值计算例子:


$ cat /tmp/num.txt
1
2
3
4
5
# 计算均值
$ awk 'BEGIN{ sum=0; } { sum+=$1; } END{ print sum/NR }' /tmp/num.txt 
3

$ cat /tmp/num.txt
1 2 3 4 5
11 22 33 44 55
10 20 30 40 50
# 计算均值
$ awk '{ sum=0; for(i=1; i<=NF; i++) sum+=$i; print sum/NF }' /tmp/num.txt 
3
33
30


awk可以自定义函数,暂时用不到,先不记录了。

你可能感兴趣的:(linux,ubuntu,bash)