awk 的匹配条件
在 awk 中, 0 表示假, 1 表示真 只有为真时, 才会执行 program 代码块
变量未声明, 变量值为空, 变是值为 0.pattern 条件都是返回为 0(假)
下面的 3 种情况都为假, 都不会有输出结果
- #awk -v i="" i{print $0} /etc/passwd
- #awk -v i=0 i{print $0} /etc/passwd
- #awk i{print $0} /etc/passwd
以下情况, 变量 A 并没有定义, 但是在前面加上!, 相当于把假取反, 也就是真了所以命令有执行结果
#awk !A{print $0} /etc/passwd 等价于 #awk !A /etc/passwd
一些比较烧脑的写法
- #awk BEGIN{i=0;print !i++,i} 解析: i=0, 为假, 先把 i 取反, 变为真, 第一个结果为 1, 再 i++ (0+1=1) , 第二个结果为 1
- 1 1
- #awk BEGIN{i=0;print !++i,i} 解析: i=0, 为假, 先 ++i(0+1=1), 再把 i 取反, 变为假, 第一个结果为 0, 再 ++i(0+1=1) , 第二个结果为 1
- 0 1
- #awk BEGIN{i=-1;print !++i,i} 解析: i=-1, 不为空, 也不为 0, 为真, 先 ++i(-1+1=0) , 再把 i 取反, 变为真, 第一个结果为 1, 再 ++i(-1+1=0) , 第二个结果为 0
- 1 0
- #awk BEGIN{i=-1;print !i++,i} 解析: i=-1, 不为空, 也不为 0, 为真, 先把 i 取反, 变为假, 第一个结果为 0, 再 i++(-1+1=0) , 第二个结果为 0
- 0 0
利用 awk 打印奇数行
- #seq 10 | awk i=!i
- 1
- 3
- 5
- 7
- 9
来解读下吧:
根据文章最开头讲的, 在 awk 中, 0 表示假, 1 表示真 只有为真时, 才会执行 program 代码块
当 awk 开始处理第一行时, 变量 i 未声明, 值为 "空", 表示假, 但是 i 取反了, 变为真了, 所以会执行 program 的动作, 但是动作省略了, 因此就是默认 print $0, 也就是输出第一行
当处理第二行文本时, i 为真, 取反后, i 为假, 所以第二行没有执行 program 的动作, 最终只打印了奇数行
为了能够更加直观的看到上述过程 0 和 1 的变化, 将 i 的值打印出来
- #seq 10 | awk {i=!i;print i,$0}
- 1 1
- 0 2
- 1 3
- 0 4
- 1 5
- 0 6
- 1 7
- 0 8
- 1 9
- 0 10
- #seq 10 | awk ++I%2
- 1
- 3
- 5
- 7
- 9
- #seq 10 | awk -v i=0 i=!i
- 1
- 3
- 5
- 7
- 9
- #seq 10 | awk NR%2
- 1
- 3
- 5
- 7
- 9
利用 awk 打印偶数行
- #seq 10 | awk -v i=1 i=!i
- 2
- 4
- 6
- 8
- 10
上面的例子, 用更详细的过程打印出来, 当 i=0 时, 不会输出那一行
- #seq 10 | awk -v i=1 {i=!i;print i,$0}
- 0 1
- 1 2
- 0 3
- 1 4
- 0 5
- 1 6
- 0 7
- 1 8
- 0 9
- 1 10
- #seq 10 | awk i++%2
- 2
- 4
- 6
- 8
- 10
- #seq 10 | awk !(NR%2)
- 2
- 4
- 6
- 8
- 10
awk 控制语句
三目表达式
语法:
条件 ? 条件为 真 时执行: 条件为 假 时执
也可以理解为:
表达式 1 ? 表达式 1 为 真 时执行的表达式 A: 表达式 1 为 假 时执行的表达式 B
例子:
awk -F: {usertype=$3<500? "系统用户" : "普通用户" ;print $1,$3,usertype} /etc/passwd
root 0 系统用户
bin 1 系统用户
nfsnobody 65534 普通用户
saslauth 499 系统用户
hunk 500 普通用户
#awk BEGIN{grep hunk44 ?var="用户存在":var="用户不存在";print var}
用户不存在
#awk -F: {$3<500 ?sum1++:sum2++;}END{print "系统用户数:"sum1,"普通用户数:"sum2} /etc/passwd
系统用户数: 19 普通用户数: 5
组合语句
所谓的组合语句, 就是大括号内有多条指令指令之间用; 分号分隔
如:
awk -F: {print $1} /etc/passwd > 单条语句
awk -F: {print "uid:"$3 ; print $1} /etc/passwd > 组合语句
if 条件判断语句
if 语法:
if(条件){语句 1; 语句 2;...}
如果 {} 中只有一条语句, 可以省略{}, 反之则必须存在{}
if 语句必须放在 {} 内
例子:
- awk -F: {if($3<5)print $0} /etc/passwd
- root:x:0:0:root:/root:/bin/bash
- bin:x:1:1:bin:/bin:/sbin/nologin
- daemon:x:2:2:daemon:/sbin:/sbin/nologin
- adm:x:3:4:adm:/var/adm:/sbin/nologin
- lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
- awk -F: {if($3<5){print "abc";print $0}} /etc/passwd
- abc
- root:x:0:0:root:/root:/bin/bash
- abc
- bin:x:1:1:bin:/bin:/sbin/nologin
这里构建一个特殊的文件
- #vim df.txt
- Filesystem 1K-blocks Used Available Use% Mounted on
- /dev/sda3 8652808 1905000 6301600 24% /
tmpfs/dev/sda6 113972 0 113972 0% > 需要注意的是, 这一行中的 / dev/sda 并不是在行首
- /dev/sda1 487652 35608 426444 8% /boot
- #awk {if($0 ~ "^/dev/sda")print $1,$5} df.txt
- /dev/sda3 24%
- /dev/sda1 8%
- #awk {if($0 ~ "/dev/sda")print $1,$5} df.txt
- /dev/sda3 24%
- tmpfs/dev/sda6 0%
- /dev/sda1 8%
所以, 现在清楚 ~ 正则匹配模式默认指的是包含了吧
另外, 前面说过, 在正则匹配模式时, 可以使用 / / 和 " " 来引用正则, 当下面这种情况出现时, 建议使用不一样的引用符号呢
- #awk {if($0 ~ //dev/sda/)print $1,$5} df.txt
- awk: {if($0 ~ //dev/sda/)print $1,$5}
- awk: ^ syntax error
当然, 使用转义也行, 只不过看起来没有那么清晰而已
- #awk {if($0 ~ /\/dev\/sda/)print $1,$5} df.txt
- /dev/sda3 24%
- tmpfs/dev/sda6 0%
- /dev/sda1 8%
判断磁盘利用率超出某个阀值
- #df|awk -F "[ %] " /^\/dev\/sd/{if($5 > 20)print $1,$5"%"} > 最后这个 % 仅仅作为字符串显示
- /dev/sda3 24%
在 Centos7 中的 awk 版本, 默认在比较数字时, 会忽略数字后面的字符, 直接进行比较
- #df|awk /^\/dev\/sd/{if($5 > 20)print $1,$5}
- /dev/sda3 20%
- /dev/sda1 23%
而同样的语句, 在 Centos6 的版本是不生效的, 请注意
- #df|awk /^\/dev\/sd/{if($5 > 20)print $1,$5}
- /dev/sda3 24%
- /dev/sda1 8%
if..else 语法:
if(条件){语句 1; 语句 2;...}else {语句 3; 语句 4;...}
如果 {} 中只有一条语句, 可以省略{}, 反之则必须存在{}
if 语句必须放在 {} 内
例子:
- #df|awk -F "[ %] " /^\/dev\/sd/{if($5 > 20){print $1,$5} else {print $1,$5,"未超出"}}
- /dev/sda3 24
/dev/sda1 8 未超出
if..elseif..else 语法
if(条件 1){语句 1; 语句 2;...}else if(条件 2){语句 3; 语句 4;...}else {语句 5; 语句 6;...}
如果 {} 中只有一条语句, 可以省略{}, 反之则必须存在{}
if 语句必须放在 {} 内
可以存在多个 elseif
例子:
命令有点长, 慢慢按语法读就会懂了
#awk -F "[ %] " /^\/dev\/sd/{if($5 > 90 ){print $1,$5,"达到 90% 以上"} else if($5 > 60) {print $1,$5,"达到 60% 以上" } else if($5 > 20) {print $1,$5,"达到 20% 以上" } else {print $1,$5,"未超出指定阀值"}} df.txt
/dev/sda3 20 未超出指定阀值
/dev/sda2 70 达到 60% 以上
/dev/sda6 100 达到 90% 以上
/dev/sda1 23 达到 20% 以上
while 循环
语法:
while(条件){语句 1;}
条件真, 进入循环; 条件假, 退出循环
例子:
统计以 root 开头的行, 每列的字符长度
- #awk -F: /^root/{i=1;while(i<=NF){print $i,length($i);i++}} /etc/passwd
- root 4
- x 1
- 0 1
- 0 1
- root 4
- /root 5
- /bin/bash 9
do..while 循环
语法:
do{语句 1;}while(条件)
无论条件真假, 至少执行一次 do 内的循环体语句
#awk BEGIN{i=100;sum=0;do{sum+=i;i++}while(i<=100);print sum}
首先执行一次 do 里面的语句, 此时 sum=100, 再来判断 while 的条件, 此时的 i++ 后等于 101,while 的条件为假, 后续也不会再执行 do 的语句块了因此最终的循环结果为 100
for 循环
语法 1:
for(初始化值; 条件; 变化方式) {语句 1;}
计算 0-100 相加的和
- #awk BEGIN{for(i=0;i<=100;i++){sum+=i};print sum}
- 5050
既然学了那么多的循环计算, 现在来作个性能比较计算一千万次
- awk
- #time awk BEGIN{for(i=0;i<=10000000;i++){sum+=i};print sum}
- 50000005000000
- real 0m1.012s
- user 0m1.009s
- sys 0m0.001s
bash 中的 for
- #time for((sum=0,i=0;i<=10000000;i++));do sum=$[sum+i];done;echo $sum
- real 1m19.933s
- user 1m15.831s
- sys 0m3.846s
- 50000005000000
调用 bc 计算器
- #time (seq -s "+" 10000000|bc)
- 50000005000000
- real 0m7.862s
- user 0m5.485s
- sys 0m0.458s
awk 的效率真不是吹的, 以后涉及到循环计算的时候记得使用
语法 2 (遍历数组)
for(变量 in 数组) {for-body}
switch
语法: (类似于 bash 脚本中的 case)
switch (表达式) { case "表达式值 1" 或 / 正则 1/ : 语句 1...[ default: 都不匹配将执行此语句 2 ] }
#awk -F: { switch($1){ case /^root/: print $0,"匹配 case 值 1"; case "ftp": print $0,"匹配 case 值 2"; default: print "默认条件不匹配"} } /etc/passwd
root:x:0:0:root:/root:/bin/bash 匹配 case 值 1
root:x:0:0:root:/root:/bin/bash 匹配 case 值 2 > 为啥会匹配这一行, 因为没有跳出循环请看下面的 break
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin 匹配 case 值 2
#awk -F: { switch($1){ case /^root/: { print $0,"匹配 case 值 1"; break }; case /^ftp/: { print $0,"匹配 case 值 2"; break }; case /^hunk/: { print $0,"匹配 case 值 3"; break }; default: print "默 认条件不匹配" } } /etc/passwd
root:x:0:0:root:/root:/bin/bash 匹配 case 值 1
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin 匹配 case 值 2
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
默认条件不匹配
hunk88:x:1000:1001::/home/hunk88:/bin/bash 匹配 case 值 3
hunk89:x:1001:50::/home/hunk89:/bin/bash 匹配 case 值 3
hunk3:x:1002:1002::/home/hunk3:/bin/bash 匹配 case 值 3
hunk4:x:1003:1003::/home/hunk4:/bin/bash 匹配 case 值 3
break
作用: 跳出 "整个" 循环
- #awk BEGIN{for(i=0;i<=5;i++){if(i==4)break;print i}}
- 0
- 1
- 2
- 3
当 i=4 的时候, 后续的循环将不再进行, 直接结束了本层的 for 循环
continue
作用: 跳出 "本次" 循环
- #awk BEGIN{for(i=0;i<=5;i++){if(i==4)continue;print i}}
- 0
- 1
- 2
- 3
- 5
当 i=4 的时候, 直接跳过本次循环, 直接进行第 5 次循环
如果有多层循环, 可以使用诸如以下格式的语法, 控制每一层的循环
brean n(数字)
continue n(数字)
next
作用: 提前结束对本行处理而直接进入下一行处理(awk 本身就是一种逐行循环)
next 与 continue 有些类似, 只是, continue 是针对 "循环" 而言的, 而 next 是针对 "逐行处理" 的 awk 模式而言的, 因此, next 是不可以出现在 BEGIN 和 END 语句块中的
- #awk {if(/line 2/)next;print $0} 1.txt
- line 1
- line 3
- line 4
- line 5
awk 数组
一般语言中的数组元素的下标以数字表示, 默认从 0 开始 awk 使用的数组是 "关联数组", 也就是说不是以数字作为下标,"数字" 下标会被 awk 转换为 "字符串"
语法:
数组名[索引表达式]
数组名["字符串"]="值" > 可使用任意字符串; 字符串要使用双引号括起来
如果某数组元素事先不存在, 在引用时, awk 会自动创建此元素, 并将其值初始化为空的字符串
- #awk BEGIN{demo["A"]="num1";demo["B"]="num2"; print demo["B"]}
- num2
- #awk BEGIN{demo["A"]="num1";demo["B"]="num2"; print demo["C"]}
只会打印出一行空值的行, 肯定是看不见的
判断数组中是否存在某元素
语法:
索引 in 数组名
以上面的一个例子来继续演示
#awk BEGIN{demo["A"]="num1";demo["B"]="num2"; if("B" in demo){print "存在数组中"}else {print "不在数组中"}}
存在数组中
#awk BEGIN{demo["A"]="num1";demo["B"]="num2"; if("C" in demo){print "存在数组中"}else {print "不在数组中"}}
不在数组中
妙用 awk 数组去除文件中重复的行
- #cat 1.txt
- line 1
- line 3
- line 2
- line 3
- line 3
- line 4
- line 5
- line 5
- #awk !arr[$0]++ 1.txt
- line 1
- line 3
- line 2
- line 4
- line 5
当然, sort 命令也是可以做到的哦
- #sort -u 1.txt
- line 1
- line 2
- line 3
- line 4
- line 5
这个地方用 uniq 去除就是不对的哦, 因为 - u 指的是 仅显示不曾重复的行 , 那 2 行 5 是连续出现的, 就是重复的行了
- #uniq -u 1.txt
- line 1
- line 3
- line 2
- line 4
遍历数组中的每个元素
语法:
for (变量 in 数组) {for 语句块}
- #awk BEGIN{demo["A"]="123";demo["B"]="456";demo["C"]="789";for(i in demo){print i,demo[i]}}
- A 123
- B 456
- C 789
demo 数组中一共有 3 个元素
删除数组和删除数组元素
delete 语法:
delete demo 删除整个数组
delete["元素"] 删除某个元素
- #awk BEGIN{demo["A"]="123";demo["B"]="456";demo["C"]="789";delete demo["C"];for(i in demo){print i,demo[i]}}
- A 123
- B 456
实例演示
统计每个匹配的字符的数量
这里以系统登录的 IP 为例: 使用之前学习过的 sort 和 uniq 命令的组合可以完成此任务
- #time last|awk $3 ~ /[0-9]/{print $3}|sort -r|uniq -c
- 43 192.168.7.200
- 31 192.168.5.1
- 8 192.168.4.1
- 1 172.18.105.86
用时如下:
- real 0m0.009s
- user 0m0.006s
- sys 0m0.003s
以 awk 来处理的话: 利用之前讲的 数组元素事先不存在, 在引用时, awk 会自动创建此元素, 并将其值初始化为空的字符串, 再对此元素再行自相加
语法公式:
awk { 数组名[统计的字段]++ } END { for (i in 数组名){ print i, 数组名[i]} }
- #time last|awk $3 ~ /[0-9]/{ ip[$3]++ } END { for(i in ip){ print ip[i],i } }
- 31 192.168.5.1
- 1 172.18.105.86
- 43 192.168.7.200
- 8 192.168.4.1
- real 0m0.004s
- user 0m0.003s
- sys 0m0.000s
统计 apahce httpd 中访问日志的 IP 数量
- #time cut -d" " -f1 /var/log/httpd/access_log|sort -nr|uniq -c
- 4004 192.168.27.6
- 159091 172.18.56.3
- 24 172.18.0.100
- real 0m0.482s
- user 0m0.444s
- sys 0m0.036s
使用 awk 的效率可是相当高的呢
- #time awk { ip[$1]++ }END{ for(i in ip){print ip[i],i} } /var/log/httpd/access_log
- 4004 192.168.27.6
- 24 172.18.0.100
- 159091 172.18.56.3
- real 0m0.058s
- user 0m0.055s
- sys 0m0.002s
统计系统中使用每种 bash 的账号
- #awk -F: { count[$NF]++ } END { for(i in count){ print count[i] ,i } } /etc/passwd
- 1 /bin/sync
- 5 /bin/bash
- 16 /sbin/nologin
- 1 /sbin/halt
- 1 /sbin/shutdown
awk 内置函数
rand 和 srand
rand()函数: 随机产生一个 0 到 1 之间的保留小数点后 6 位的小数值
- #awk BEGIN{rand();print rand()}
- 0.291066
srand()函数: 采用当前时间作为随机计数器的种子, 这样以秒为间隔, 随机数就能滚动随机生成了
- awk BEGIN{srand();print srand()}
- 1519348286
srand 和 rand 应该组合使用, 以便 rand()能够产生随机数值
- #awk BEGIN{srand();print rand()}
- 0.0114214
- #awk BEGIN{srand();print rand()}
- 0.0296973
- int
作用: 截取整数部分的值(不是四舍五入)
- #awk BEGIN{srand();print int(rand()*100)}
- 32
- #awk BEGIN{srand();print int(rand()*100)}
- 18
- length()
作用: 返回指定字符串的长度
length 函数可以省略传入的参数, 当省略参数时, 默认使用 "$0" 作为参数
- #awk BEGIN{var="ABCDEFG";print length(var)}
- 7
- #awk -F: {print $1,length($1)} /etc/passwd
- root 4
- bin 3
- daemon 6
- sub(r,s,[t])
作用: 对 t 字符串进行在指定范围内 r 查找匹配的内容, 并将第一个匹配的内容替换为 s 类似于 sed 中的 s/A/B/
- #echo "2018-2-23"|awk sub(/-/,":",$0)
- 2018:2-23
- gsub(r,s,[t])
作用: 对 t 字符串进行在指定范围内 r 查找匹配的内容, 并将匹配的内容全部替换为 s 类似于 sed 中的 s/A/B/g 全局替换
- #echo "2018-2-23"|awk gsub(/-/,":",$0)
- 2018:2:23
- index(r,[t])
作用: 对 t 字符串进行在指定范围内 r 查找匹配的内容, 如果匹配的内容存在于当前行, 则返回字符串位于当前行的位置如果没有匹配的内容, 将返回 0
- #awk {print index($0,"3"),$0} 1.txt
- 0 line 1
6 line 3 > 3 存在于本行, 且位于本行的第 6 个字符
0 line 2
6 line 3 > 3 存在于本行, 且位于本行的第 6 个字符
6 line 3 > 3 存在于本行, 且位于本行的第 6 个字符
- 0 line 4
- 0 line 5
0 line 5 > 不存在匹配的内容, 返回 0
split(s,array,[r])
作用: 以 r 为分隔符, 切割字符串 s, 并将切割后的结果保存至 array 所表示的数组中, 第一个索引值为 1, 第二个索引值为 2, 从而动态的创建数组
- #echo "2018-2-23"|awk { split($1,arr,"-") } END { for(i in arr) {print arr[i]} }
- 2018
- 2
- 23
被 split 函数分割后的数组的元素下标从 1 开始
- #echo "2018-2-23"|awk { split($1,arr,"-") } END { print arr[0] }
- #echo "2018-2-23"|awk { split($1,arr,"-") } END { print arr[1] }
- 2018
- #echo "2018-2-23"|awk { split($1,arr,"-") } END { print arr[2] }
- 2
split 函数默认返回值就是分割以后的数组元素个数
- #echo "2018-2-23"|awk { arrleng=split($1,arr,"-") } END { print arrleng }
- 3
- [root@7-ansible-0 ~]#echo "2018-2-23-5"|awk { var=split($1,arr,"-") } END { print var }
- 4
system 函数
作用: 调用 Linux 系统命令
注意:
空格是 awk 中的字符串连接符, 如果 system 中需要使用 awk 中的变量可以使用空格分隔, 或者说除了 awk 的变量外其他一律用 " " 引用起来
- #awk BEGIN{system("uname -r")} > 系统命令记得要用双引号引用
- 3.10.0-693.el7.x86_64
- #awk BEGIN{var="abcd";system("echo 空格"var)} > 使用 system 函数引用 awk 变量的时候, 需要把变量名写在双引号外面, 而且那个空格是必须的
- abcd
awk 自定义函数
语法:
function 函数名 ( 形参 1, 形参 2, ... ) {
语句块
return 返回变量名
}
例子:
- function max(v1,v2){
- v1>v2?var=v1:var=v2
- return var
- }
BEGIN{print max(a,b)} > 这里的是实参, 必须要与形参格式一一对应并且这一行就是 awk 后面跟的命令参数
如果以下行写死的情况下, 是不需要在调用的时候 awk -v 指定实参的
BEGIN{a=3;b=10;print max(a,b)} >
调用方式:
- #awk -v a=30 -v b=20 -f fun.awk
- 30
编写自定义函数的时候, 建议后缀名为. awk
在 bash 脚本中调用 awk 脚本的方法
#!/bin/awk -f > 仅仅把 bash 脚本首行修改为这一行
执行的时候, 记得不能以 bash 来执行哦
- #chmod +x fun.awk
- ./fun.awk -v a=30 -v b=20
实例:
统计实时链接的 IP
- #netstat -tan
- Active Internet connections (servers and established)
- Proto Recv-Q Send-Q Local Address Foreign Address State
- tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
- tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN
- tcp 0 52 192.168.5.101:22 192.168.5.1:53134 ESTABLISHED
- tcp6 0 0 :::22 :::* LISTEN
- tcp6 0 0 ::1:25 :::* LISTEN
- #netstat -tan | awk /^tcp\>/{split($5,ip,":");count[ip[1]]++} END {for (i in count) {print i,count[i]} }
- 192.168.5.1 1
- 0.0.0.0 2
统计文件中每个单词的次数
- root:x:0:0:root:/root:/bin/bash
- #awk -F: /^root/{ for(i=1;i<=NF;i++i){word[$i]++} } END { for(i in word){print "出现次数:"word[i],"字符:"i} } /etc/passwd
出现次数: 1 字符:/bin/bash
出现次数: 1 字符: x
出现次数: 1 字符:/root
出现次数: 2 字符: 0
出现次数: 2 字符: root
按顺序遍历 awk 数组元素
- #awk -v ts="aa-bb-11-22" BEGIN{split(ts,arr,"-");for( i in arr){print i,arr[i]}}
- 4 22
- 1 aa
- 2 bb
- 3 11
使用 for 循环来遍历并且按顺序列出
- #awk -v ts="aa-bb-11-22" BEGIN{var=split(ts,arr,"-");for(i=1;i<=var;i++){print i,arr[i]}}
- 1 aa
- 2 bb
- 3 11
- 4 22
计算平均分
#cat file.txt
张三 男 85
李四 男 96
赵云 女 99
梦回 女 100
王者 男 74
#awk {if($2=="男"){inum++;isum+=$3}else{ynum++;ysum+=$3}}END{printf "男:%.2f\n 女:%.2f\n",isum/inum,ysum/ynum} file.txt
男: 85.00
女: 99.50
用数组功能实现
#awk {num[$2]++;sum[$2]+=$3}END{for(sex in num){print sex,num[sex],sum[sex]/num[sex]}} file.txt
男 3 85
女 2 99.5
将当前并发连接数大于某次数的 IP 添加至 iptables 拒绝列表中
ss -nt|awk -F "[ :]+" /^ESTAB/{IP[$(NF-2)]++}END{for (i in IP){if (IP[i] >=1){system("iptables -A INPUT -s"i"-j REJECT")} }}
提取字符串中的数字
- #echo Yd$C@M05MB%9&Bdh7dq+YVixp3vpw|awk split($0,arr,""){for (i in arr){if (arr[i] ~ /[0-9]/){printf arr[i]}}}
- 37059
- #echo Yd$C@M05MB%9&Bdh7dq+YVixp3vpw|awk -F "" {for(i=1;i<=NF;i++){if ($i ~ /[0-9]/){ str=$i;str1=(str1 str) }} print str1}
- 05973
备注:
str1=str1=(str1 str)每次 str1 存的就是上一次的值, 括号内的空格是字符串连接
运用此方法, 可以拓展到一些其他的功能, 比如提取大小写的英文字母或者是一些特殊的符号只需要更改 [0-9] 这个条件
[a-zA-Z] 提取大小写英文字符
[^0-9a-zA-Z] 提取除了数字, 大小写英文以外的字符
AWK ( 二 )
来源: http://www.bubuko.com/infodetail-2504706.html