awk 条件判断与正则、12个实用函数

一、awk与条件判断、循环

(一) 条件判断

① if结构 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if [ xxx ];then
xxx
fi
 
格式:
awk 选项 '正则,地址定位{awk语句}'  文件名
 
{ if(表达式){语句1;语句2;...}}
#$3为uid
 
awk -F:  '{if($3>=500 && $3<=60000) {print $1,$3} }' passwd
 
awk -F:  '{if($3==0) {print $1"是管理员"} }' passwd
root是管理员
 
awk  'BEGIN{if('$(id -u)'0) {print "admin"} }'
admin

② if...else结构 

1
2
3
4
5
6
7
8
9
10
11
12
if [ xxx ];then
  xxxxx
else
  xxx
fi
 
格式:
{if(表达式){语句;语句;...}else{语句;语句;...}}
 
awk -F:  '{ if($3>=500 && $3 != 65534) {print $1"是普通用户"} else {print $1,"不是普通用户"}}' passwd
 
awk 'BEGIN{if( '$(id -u)'>=500 && '$(id -u)' !=65534 ) {print "是普通用户"} else {print "不是普通用户"}}'

③ if...elif...else结构

1
2
3
4
5
6
7
8
9
10
11
if [xxxx];then
  xxxx
elif [xxx];then
  xxx
....
else
...
fi
 
格式:
{ if(表达式1){语句;语句;...}else if(表达式2){语句;语句;...}else if(表达式3){语句;语句;...}else{语句;语句;...}}

范例:

1、打印用户类型

1
2
3
4
awk -F: '{ if($3==0) {print $1,":是管理员"} else if($3>=1 && $3<=499 || $3==65534 ) {print $1,":是系统用户"} else {print $1,":是普通用户"}}'  /etc/passwd
root :是管理员
sys :是系统用户
zjz :是普通用户

2、打印用户个数

1
2
3
4
awk -F: '{ if($3==0) {i++} else if($3>=1 && $3<=499 || $3==65534 ) {j++} else {k++}};END{print "管理员个数为:"i "\n系统用户个数为:"j"\n普通用户的个数为:"k }'  /etc/passwd
管理员个数为:1
系统用户个数为:27
普通用户的个数为:2

(二)循环语句

① for循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
##打印1~5
for ((i=1;i<=5;i++));do echo $i;done
 
awk 'BEGIN { for(i=1;i<=5;i++) {print i} }'
 
打印1~10中的奇数
for ((i=1;i<=10;i+=2));do echo $i;done|awk '{sum+=$0};END{print sum}'
awk 'BEGIN{ for(i=1;i<=10;i+=2) {print i} }'
awk 'BEGIN{ for(i=1;i<=10;i+=2) print i }'
 
#计算1-5的和
awk 'BEGIN{sum=0;for(i=1;i<=5;i++) sum+=i;print sum}'
awk 'BEGIN{for(i=1;i<=5;i++) (sum+=i);{print sum}}'
awk 'BEGIN{for(i=1;i<=5;i++) (sum+=i);print sum}'

② while循环

1
2
3
4
5
6
7
8
9
打印1-5
# i=1;while (($i<=5));do echo $i;let i++;done
 
# awk 'BEGIN { i=1;while(i<=5) {print i;i++} }'
打印1~10中的奇数
# awk 'BEGIN{i=1;while(i<=10) {print i;i+=2} }'
计算1-5的和
# awk 'BEGIN{i=1;sum=0;while(i<=5) {sum+=i;i++}; print sum }'
# awk 'BEGIN {i=1;while(i<=5) {(sum+=i) i++};print sum }'

③ 嵌套循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
嵌套循环:
#!/bin/bash
for ((y=1;y<=5;y++))
do
  for ((x=1;x<=$y;x++))
  do
    echo -n $x 
  done
echo
done
 
awk 'BEGIN{ for(y=1;y<=5;y++) {for(x=1;x<=y;x++) {printf x} ;print } }'
 
 
awk 'BEGIN { for(y=1;y<=5;y++) { for(x=1;x<=y;x++) {printf x};print} }'
1
12
123
1234
12345
 
awk 'BEGIN{ y=1;while(y<=5) { for(x=1;x<=y;x++) {printf x};y++;print}}'
1
12
123
1234
12345
 
打印乘法口诀表shell的几种写法:
#!/bin/bash
for i in $(seq 9)
do
    for j in $(seq $i)
    do
        echo -n "$j*$i=$[$i * $j] "
    done
    echo
done
 
seq 9 | sed 'H;g' | awk -v RS='' '{for (i=1;i<=NF;i++)printf("%dx%d=%d%s",i,NR,i*NR,i==NR?"\n":"\t")}'
awk 'BEGIN{for(y=1;y<=9;y++) { for(x=1;x<=y;x++) printf x"*"y"="x*y"\t";print} }'
awk 'BEGIN{i=1;while(i<=9){for(j=1;j<=i;j++) {printf j"*"i"="j*i"\t"};print;i++ }}'
awk 'BEGIN{for(i=1;i<=9;i++){j=1;while(j<=i) {printf j"*"i"="i*j"\t";j++};print}}'
 
###不够人性化
awk '{for(i=1;i<=9;i++){for(j=1;j<=i;j++){printf "%d*%d=%d ",j,i,j*i}printf "\n"}}'
 
循环的控制:
break    条件满足的时候中断循环
continue  条件满足的时候跳过循环
 
awk 'BEGIN{for(i=1;i<=5;i++) {if(i==3) break;print i} }'
1
2
 
awk 'BEGIN{for(i=1;i<=5;i++){if(i==3) continue;print i}}'
1
2
4
5

二、awk与算数运算

1
2
3
4
5
6
+ - * / %(模) ^(幂2^3)
可以在模式中执行计算,awk都将按浮点数方式执行算术运算
awk 'BEGIN{print 1+1}'
awk 'BEGIN{print 1**1}'
awk 'BEGIN{print 2**3}'
awk 'BEGIN{print 2/3}'

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
awk -F: '{if($3>=1000)print $1,$3}'  /etc/passwd
zjz 1000
zjz1 1001
 
awk -F: '{if($NF=="/bin/bash")print $1}' /etc/passwd
root
zjz
zjz1
 
awk -F: '{if($3>=1000){print "Common user:%s\n",$1}else {print "root or Sysuser:%s\n",$1}}'   /etc/passwd
root or Sysuser:%s
 sshd
root or Sysuser:%s
 apache
Common user:%s
 zjz
Common user:%s
 zjz1
 
df -hT |awk -F% '/^\/dev\/sda1/{print $1}'|awk '$NF>=10{print $1,$6}'
/dev/sda1 13
 
awk 'BEGIN{test=20;if(test>90){print "very good"}else if (test>60){print "good"}else {print "no pass"} }'
no pass

打印行前或者行后,NR:行号,$NF:最后一列。(大于>、小于<、等于==)

1
2
3
4
5
$ cat zjz.txt    |  awk '{if(NR>6) print $NF}'
init.sh
django.log.2020-11-09.gz
backend.py
cassandra-env.sh

将当前目录下大于 10K 的文件转移到 /tmp 目录,再按照文件大小顺序,从大到小输出文件名。

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
 
# 目标目录
DIRPATH='/tmp'
# 查看目录
FILEPATH='.'
 
find "$FILEPATH" -size +10k -type f | xargs -i mv {} "$DIRPATH"
 
ls -lS "$DIRPATH" | awk '{if(NR>1) print $NF}'

打印访问次数大于21的ip

1
2
3
4
5
cat access1.log |cut -d ' ' -f 1 | sort -nr  |uniq -c  | sort -nr  | head -n 20 | awk -F" " '{if ($1 >= 21) print $0}'
 896 60.21.253.82
  75 216.83.59.82
  21 61.241.50.63
  21 211.95.50.7

三、awk流程控制

break、continue、next、nextfile、exit

1、break和continue

break:可退出for、while、do…while、switch语句。
continue:可让for、while、do…while进入下一轮循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
awk '
BEGIN{
  for(i=0;i<10;i++){
    if(i==5){
      break
    }
    print(i)
  }
 
  # continue
  for(i=0;i<10;i++){
    if(i==5)continue
    print(i)
  }
}'

2、next和nextfile

next:会在当前语句处立即停止后续操作,并读取下一行,进入循环顶部。
例如,输出除第3行外的所有行。

1
2
awk 'NR==3{next}{print}' a.txt
awk 'NR==3{getline}{print}' a.txt

nextfile:会在当前语句处立即停止后续操作,并直接读取下一个文件,并进入循环顶部。

例如,每个文件只输出前2行:

1
awk 'FNR==3{nextfile}{print}' a.txt a.txt

3、exit

直接退出awk程序。
注意,END语句块也是exit操作的一部分,所以在BEGIN或main段中执行exit操作,也会执行END语句块。
如果exit在END语句块中执行,则立即退出。
所以,如果真的想直接退出整个awk,则可以先设置一个flag变量,然后在END语句块的开头检查这个变量再exit。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
BEGIN{
    ...code...
    if(cond){
        flag=1
        exit
    }
}
{}
END{
    if(flag){
        exit
    }
    ...code...
}
 
awk '
    BEGIN{print "begin";flag=1;exit}
    {}
    END{if(flag){exit};print "end2"}
'

exit可以指定退出状态码,如果触发了两次exit操作,即BEGIN或main中的exit触发了END中的exit,且END中的exit没有指定退出状态码时,则采取前一个退出状态码。

1
2
3
4
5
6
7
$ awk 'BEGIN{flag=1;exit 2}{}END{if(flag){exit 1}}'
$ echo $?
1
 
$ awk 'BEGIN{flag=1;exit 2}{}END{if(flag){exit}}'  
$ echo $?
2

四、awk与正则

https://www.cnblogs.com/ginvip/p/6352157.html

五、12个实用函数

1、length()

返回字符串或字段的长度。

1
echo "hello world" | awk '{print length($0)}'  # 输出:11 

2、substr(s, start, [length])

返回字符串 s 中从位置 start 开始、长度为 length 的子串。如果未指定 length,则返回从 start 到字符串结尾的子串

1
echo "abcdef" | awk '{print substr($0, 2, 3)}'  # 输出:bcd

3、index(s, t)

返回字符串 t 在字符串 s 中首次出现的位置。如果未找到,则返回 0

1
echo "hello world" | awk '{print index($0, "world")}'  # 输出:7

4、match(s, regex)

测试字符串 s 是否与正则表达式 regex 匹配,如果匹配成功,RSTART 变量设置为匹配的起始位置,RLENGTH 为匹配的长度

1
echo "abcdef" | awk '{if (match($0, /c.*f/)) print RSTART, RLENGTH}'  # 输出:3 4

5、split(s, a, [regex])

将字符串 s 通过 regex 分割成数组 a。如果未提供 regex,则使用默认字段分隔符。

1
2
3
4
echo "apple,banana,orange" | awk '{n=split($0, a, ","); for (i=1; i<=n; i++) print a[i]}' 
# 输出:apple
# banana
# orange

6、sprintf(fmt, expr, ...)

返回格式化字符串,类似 printf

1
echo "10" | awk '{print sprintf("%.2f", $1)}'  # 输出:10.00 

7、tolower(str)

将字符串 str 中的所有字符转换为小写。

1
echo "HELLO" | awk '{print tolower($0)}'  # 输出:hello

8、toupper(str)

将字符串 str 中的所有字符转换为大写。

1
echo "hello" | awk '{print toupper($0)}'  # 输出:HELLO

9、gsub(regex, replacement, [target])

在 target 中用 replacement 替换所有匹配 regex 的部分。如果未提供 target,则应用于当前行。

1
2
3
4
5
6
7
8
9
echo "foo bar baz" | awk '{gsub(/bar/, "baz", $0); print}'  # 输出:foo baz baz
 
grep -nr image: ./*.yml | awk '{ gsub(/"/, ""); print $3 }'
172.30.247.81:5000/app-router:v3.1.4-20241211
172.30.247.81:5000/common-util:1-20180408
 
# 替换前
"172.30.247.81:5000/app-router:v3.1.4-20241211"
"172.30.247.81:5000/common-util:1-20180408"

10、sub(regex, replacement, [target])

在 target 中用 replacement 替换第一个匹配 regex 的部分。

1
echo "foo bar baz" | awk '{sub(/bar/, "baz", $0); print}'  # 输出:foo baz baz

11、strftime([format [, timestamp]])

返回格式化的时间字符串,timestamp 为时间戳。如果未指定,则使用当前时间。

1
awk 'BEGIN {print strftime("%Y-%m-%d %H:%M:%S")}'  # 输出当前时间,格式为:YYYY-MM-DD HH:MM:SS

12、srand([seed])

用于初始化随机数生成器的种子,如果未提供 seed,则使用当前时间。

1
2
srand([seed])
用于初始化随机数生成器的种子,如果未提供 seed,则使用当前时间。

  

 

 

 

 https://www.junmajinlong.com/shell/awk/awk_process_control_statement2/    精通awk系列

posted @   凡人半睁眼  阅读(23915)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示