awk 表示分隔符的方法
转自:https://blog.csdn.net/wzb56_earl/article/details/17511213
a). awk的选项: -F ‘分割字符’
b). awk的全局变量:FS # Field Separator
c). awk的默认的分隔符:是空白符包括: 空格、制表符、换行符
打印系统中各个用户使用的shell
# cat /etc/passwd | awk -F : '{ print $1, $7}'
或者
# cat /etc/passwd | awk 'BEGIN{ FS = ":"; } {print $1, $7}'
多字符分隔符
# echo "abcdef" | awk -F cd '{print $1, $2}'
ab ef
多种字符作为分隔符
# echo "abcdefg" | awk -F [bdf] '{print $1, $2, $3, $4}'
a c e g
特殊的多字符分隔符: ||
# echo "abc||def||hij" | gawk -F'\\|\\|' '{print #1, #2, #3}'
abc def hij
# echo "abc||def||hij" | gawk -F'\\\|\\\|' '{print #1, #2, #3}'
gawk: warning: escape sequence `\|' treated as plain `|'
abc def hij
# echo "abc||def||hij" | gawk -F'\\|\\|' '{print #1, #2, #3}'
abc def hij
# echo "abc||def||hij" | gawk -F"\\|\\|" '{print #1, #2, #3}'
gawk: warning: escape sequence `\|' treated as plain `|'
abc||def||hij
# echo "abc||def||hij" | gawk -F"\\\|\\\|" '{print #1, #2, #3}'
abc def hij
# echo "abc||def||hij" | gawk -F"\\\\|\\\\|" '{print #1, #2, #3}'
abc def hij
匹配输出
awk '/aaa/{print}' file
awk '$1 ~ /aaa/{print}' file
# $1匹配包含点"."的
awk '$1 ~ /\./{print}' file
不匹配输出
awk '!/aaa/{print}' file
awk '$1 !~ /aaa/{print}' file
# $1不匹配包含点"."的
awk '$1 !~ /\./{print}' file
设置变量
awk -v
例如:
现有如下数据:
$ cat a.txt
1 this,is,a,testfile
2 Are you ready?
3 This is a platabout linux
4 I like this.
执行如下命令,每行第一项加1:
$ awk -va=1 '{print $1,$1+a}' a.txt
1 2
2 3
3 4
4 5
也可以使用如下命令设置多个变量:
$ awk -va=1 -vb=s '{print $1,$1+a,$1b}' a.txt
1 2 1s
2 3 2s
3 4 3s
4 5 4s
通过awk脚本来运行awk命令
awk -f awk脚本 文件名
例如:
awk -f file.awk test
多个分隔符
使用-或|作为分隔符
awk -F ‘[-|]’ ‘{print $3;}’ data
使用[]作为分隔符
awk -F'[][]'
输出列数
测试数据
# cat a.txt
01 02 03 04 05 06 07 08 09 10
11 12 13 14 15 16 17 18 19 20
输出前几列
# awk '{for(i = 1; i <= 5; i++) printf("%s ", $i); printf("\n")}' a.txt
01 02 03 04 05
11 12 13 14 15
输出中间几列
# awk '{for(i = 3; i <= 8; i++) printf("%s ", $i); printf("\n")}' a.txt
03 04 05 06 07 08
13 14 15 16 17 18
输出最后几列
# awk '{for(i = NF - 5 + 1; i <= NF; i++) printf("%s ", $i); printf("\n")}' a.txt ## 最后5列
06 07 08 09 10
16 17 18 19 20
扩展
# awk '{for(i = 2; i <= 5; i++) printf("%s ", $i); {print $8, $9}}' a.txt
02 03 04 05 08 09
12 13 14 15 18 19
不输出最后一列
awk '{$NF="";print $0}' file
BEGIN和END模块
统计$1的次数,并输出大于1次的行
awk '{c[$1]++;} END {for (i in c) {if(c[i]>1) print i "\t" c[i]}}' file.txt
## 多行的写法
awk '{
c[$1]++;
}
END {
for (i in c) {
if(c[i]>1)
print i "\t" c[i]
}
}' file.txt
例:判断输出值是否大于100,是输出2,否输出1,非数字输出0
awk 'BEGIN {found=0} {if ($1 ~ /^[0-9]+$/) {print ($1 >= 100 ? 2 : 1); found=1}} END {if (found==0) {print 0}}'
解释:使用BEGIN模块初始化一个变量found为0。然后在每行中判断$1是否为数字,如果是则输出相应的结果,并将found设为1。最后在END模块中判断found是否为0,如果是则输出0。
FS\OFS\RS\ORS
FS :是列分隔符,默认是空格
OFS:是输出列的分隔符
RS :是行分隔符,默认是空格(Record Separator)
ORS:是输出行的分隔符
即RS表示的是awk操作最小单位的边界,而FS是这个最小单位中分割的符号

echo "a:b:c:d" | awk '{print $0}'
a:b:c:d
echo "a:b:c:d" | awk 'BEGIN{RS=":"}{print $0}'
a
b
c
d
echo "a:b:c:d" | awk 'BEGIN{RS=":";ORS="****"}{print $0}'
a****b****c****d
NR和FNR的区别
NR:表示当前记录数
FNR:也表示当前记录数,但是FNR的作用域只在一个文件内.如果重新打开文件,FNR会从1开始
测试文件aaa,cccc
[root@Blackghost test2]# cat aaa //测试文件aaa
1111:23434:zhang
hoadsf:asdf:ccc
[root@Blackghost test2]# cat ccc //测试文件ccc
1111:23434:zhang
hoadsf:asdf:ccc
tank:zhang:x20342
ying:zhasdf:72342
hosa:asdfa:2345sdf
一个文件中NR,FNR
[root@Blackghost test2]# awk '{print NR;print FNR;print $0;}' aaa
1 //NR
1 //FNR
1111:23434:zhang
2
2
hoadsf:asdf:ccc
多个文件中NR,FNR
[root@Blackghost test2]# awk '{print NR;print FNR;print $0;}' aaa ccc
1
1
1111:23434:zhang
2 //NR
2 //FNR
hoadsf:asdf:ccc
3 //NR
1 //FNR 下面的数据是来自ccc,所以NFR重置为1
1111:23434:zhang
4
2
hoadsf:asdf:ccc
5
3
tank:zhang:x20342
6
4
ying:zhasdf:72342
7
5
hosa:asdfa:2345sdf
if
筛选tcp中接受或发送的有堆积的链接情况
netstat -tanp | awk '{if ($2 > 0 || $3 > 0) print $0}'
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 36 172.17.1.12:1229 11.19.14.15:8763 ESTABLISHED 29280/sshd: root@pt
if else
awk '{if ($1==1) print "A"; else if ($1==2) print "B"; else print "C"}'
grep '接口耗时:' test.log|cut -d "m" -f 1 |cut -d ":" -f 2|awk 'BEGIN {count=ms1=ms2=ms3=0}{if($1<1) ms1++;else if($1>=1&&$1<=5) ms2++;else ms3++;count++}END{printf ("ms1,ms1占比 %s,%.2f%%\n",ms1,ms1/count*100);printf ("ms2,ms2占比 %s,%.2f%%\n",ms2,ms2/count*100);printf ("ms3,ms3占比 %s,%.2f",ms3,ms3/count*100,"%")}'
ms1,ms1占比 0 , 0.00 %
ms2,ms2占比 17 , 89.47 %
ms3,ms3占比 2 , 10.53 %
匹配特殊字符
.-->还没找到办法
abb="abc_78[edd0.2]"
awk '{print $0;if($0~'"$abb"'){print "no";exit}}' file
awk '{print $0;if($0~/abc_78\[edd0.2\]/){print "no";exit}}' file
# 下列命令还未实现
abb="."
tac dishttp.INFO| grep REQUEST | grep false | awk '{print $10}' | grep ? | awk -F'?' '{print $1}' | awk -v akey=$abb '{if($NF~'"$abb"'){print $0}}' | more
函数
substr()截取字段
# echo "123456789 3333344" | awk '{print substr($1,5,2)}'
56
$1指的是第一列,也就是123456789
5指的是从第5个字符开始
2指的是截取2个字符
# echo "12345678dsdsd" | cut -c1-10
12345678ds
以字符为单位进行割接
# a=123456789;echo ${a:4:2}
56
这个是从0开始算,所以是4:2
getline函数
得到行,获取当前行的下一行。
getline命令是我个人认为awk最强大的一个命令。因为它彻底改变了awk的运行逻辑。awk本质上就是一个for循环,它每次对输入文件的一行进行处理,然后转而执行下一行,直到整个文件的每一行都被执行完毕。整个过程是自动的,你无需做什么。但是,getline命令却可以让你去控制循环。当然,getline命令执行后,awk会设置NF,NR,FNR和$0等这些内部变量。
打印出从1到10之间的偶数
$ seq 10 | awk '{getline; print $0}'
2
4
6
8
awk首先读取到了第一行,就是1,然后getline,就得到了1下面的第二行,就是2,因为getline之后,awk会改变对应的NF,NR,FNR和$0等内部变量,所以此时的$0的值就不再是1,而是2了,然后将它打印出来。以此类推,就可以得到上面的结果。
只打印出奇数行
$ seq 10 | awk '{print $0; getline}'
1
3
5
7
奇偶行对调打印
$ seq 10 | awk '{getline tmp; print tmp; print $0}'
2
1
4
3
6
5
8
7
10
9
将getline得到的下一行的内容放在了tmp这个变量里,因此NF,NR,FNR和$0等内部变量并不会被改变。
从另外一个文件中读取内容
$ awk '{printf "%s ", $0; getline < "b.txt"; print $0}' a.txt
1 6
2 7
3 8
4 9
5 20
通过getline得到系统的当前时间
$ awk 'BEGIN {"date" | getline; close("date"); print $0}'
Tue May 10 07:50:51 PDT 2016
split
awk的内建函数split允许你把一个字符串分隔为单词并存储在数组中。你可以自己定义域分隔符或者使用现在FS(域分隔符)的值。1在awk中是多维数组的时候,若需要访问数组中某一元素内部的字符,必须使用split(item,subscr,SUBSEP)函数来访问单独的下标分量。
split(),对于从字段中提取“子字段”有很大用处,split(string,aray,separator),string 是要被分解到名为array的元素的输入字符串,数组的下标从1开始到n,n即为数组中元素的个数,元素根据separator分隔符来分解,separator可以支持一个完整的正则表达式。默认为FS。
格式:
split (string, array, field separator)
split (string, array) -->如果第三个参数没有提供,awk就默认使用当前FS值。
例子:
例:替换分隔符
time="12:34:56"
out=`echo $time | awk '{split($0,a,":");print a[1],a[2],a[3]}'`
echo $out
例:计算指定范围内的和(计算每个人1月份的工资之和)
[root@test ~]# cat test.txt
Tom 2012-12-11 car 53000
John 2013-01-13 bike 41000
vivi 2013-01-18 car 42800
Tom 2013-01-20 car 32500
John 2013-01-28 bike 63500
[root@test ~]# awk '{split($2,a,"-");if(a[2]==01){b[$1]+=$4}}END{for(i in b)print i,b[i]}' test.txt
vivi 2800
Tom2500
John4500
例:利用split做格式转换
1.1.1.1 3 2024-03-12_04:59:00|2024-03-12_10:38:00|2024-03-12_21:23:00
shell中,如何将上面的写法写成下面的样子
1.1.1.1 3 2024-03-12_04:59:00 2024-03-12
1.1.1.1 3 2024-03-12_10:38:00 2024-03-12
1.1.1.1 3 2024-03-12_21:23:00 2024-03-12
# echo "1.1.1.1 3 2024-03-12_04:59:00|2024-03-12_10:38:00|2024-03-12_21:23:00" | awk -F'\t' '{split($3, a, "|"); for (i in a) { split(a[i], b, "_"); print $1 "\t" $2 "\t" a[i] "\t" b[1]}}'
1.1.1.1 3 2024-03-12_04:59:00 2024-03-12
1.1.1.1 3 2024-03-12_10:38:00 2024-03-12
1.1.1.1 3 2024-03-12_21:23:00 2024-03-12
参考:
https://blog.csdn.net/lovedingd/article/details/121698445