Awk学习笔记
高级用法
-
文本
cp /etc/passwd ./passwd.txt # cat passwd.txt root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin messagebus:x:103:104::/nonexistent:/usr/sbin/nologin systemd-timesync:x:104:105:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin pollinate:x:105:1::/var/cache/pollinate:/bin/false sshd:x:106:65534::/run/sshd:/usr/sbin/nologin syslog:x:107:113::/home/syslog:/usr/sbin/nologin uuidd:x:108:114::/run/uuidd:/usr/sbin/nologin tcpdump:x:109:115::/nonexistent:/usr/sbin/nologin tss:x:110:116:TPM software stack,,,:/var/lib/tpm:/bin/false landscape:x:111:117::/var/lib/landscape:/usr/sbin/nologin fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin usbmux:x:113:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin user:x:1000:1000:root:/home/user:/bin/bash lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false bind:x:114:119::/var/cache/bind:/usr/sbin/nologin
Awk基本语法结构
awk 'BEGIN { initialization } pattern { action } END { finalization }' file.txt
-
BEGIN 块
(可选):在处理输入之前执行一次的初始化操作,例如设置变量的初始值。 -
pattern
:模式,用于匹配输入中的特定行。 -
action
:动作,在匹配的行上执行的操作。 -
END块
(可选):在处理输入完毕后执行一次的收尾操作,例如输出最终结果。
模式和动作的使用
-
模式:用于匹配特定的行或条件,可以使用正则表达式、关系表达式等。
-
动作:在匹配行上执行的操作,可以是打印、赋值、计算等。
# 示例:打印包含"pattern"的行 awk '/pattern/ { print }' passwd.txt
-
打印行号及行内容
awk '{print NR,$0}' passwd.txt
-
打印以root开头的行
awk -F: '/^root/{print}' passwd.txt
-
打印以bash结尾的行
awk -F: '/bash$/{print}' passwd.txt
-
打印第3列值<500的行
awk -F: '$3<500{print}' passwd.txt
-
打印第3列值>500&&<1000的行
awk -F: '$3>500&&$3<1000{print}' passwd.txt
-
打印偶数行并显示行数
awk 'NR%2==0{print NR,$0}' passwd.txt
-
打印奇数行并显示行数
awk 'NR%2!=0{print NR,$0}' passwd.txt
-
统计行数
awk 'BEGIN{x=0} {x++} END {print x}' passwd.txt
内置变量
NR
:当前行的行号。NF
:当前行的字段数。$0
:当前行的内容。$1
、$2
、$3
等:当前行的第一个、第二个、第三个字段等。
内置函数
-
length(str)
:返回字符串的长度。awk 'BEGIN { str = "Hello, World!"; len = length(str); print len }' # 输出: 13
-
substr(str, start, length)
:返回字符串的子串。awk 'BEGIN { str = "Hello, World!"; sub = substr(str, 1, 5); print sub }' # 输出: Hello
-
index(str, substr)
:返回子串在字符串中的位置。awk 'BEGIN { str = "Hello, World!"; pos = index(str, "World"); print pos }' # 输出: 8
-
split(str, array, sep)
:将字符串拆分为数组元素。awk 'BEGIN { str = "apple,banana,orange"; split(str, fruits, ","); print fruits[2] }' # 输出: banana
-
toupper(str)
:将字符串转换为大写。awk 'BEGIN { str = "Hello, World!"; upper = toupper(str); print upper }' # 输出: HELLO, WORLD!
-
tolower(str)
:将字符串转换为小写。awk 'BEGIN { str = "Hello, World!"; lower = tolower(str); print lower }' # 输出: hello, world!
-
int(x)
:返回不大于x的最大整数。awk 'BEGIN { x = 4.7; result = int(x); print result }' # 输出: 4
-
说明
!a[$0]++ 的含义是: 判断行的值是否已经存在于数组a中,如果不存在,则将该字段添加到数组中,并将其值加1 a[$0]++的含义是: 将第行的值作为数组a的键,然后将该键对应的值加1
-
去除重复行
# 以第7列为基准去除重复行 awk -F: '!a[$7]++{print $7}' passwd.txt # 输出 /bin/bash /usr/sbin/nologin /bin/sync /bin/false
-
利用awk找出文本中空白行并统计行数
awk '/^$/{sum++}END{print sum}' file
-
统计重复行次数
# 统计文件中不同单词的出现次数 awk -F: '{!count[$7]++} END {for(i in count) print i, count[i]}' passwd.txt 或者 awk -F: '{ count[$7]++ } END { for (i in count) print i, count[i] }' passwd.txt # 输出 /bin/sync 1 /bin/bash 2 /bin/false 3 /usr/sbin/nologin 29
-
条件语句和循环结构:Awk支持if-else语句和for循环,可实现更复杂的逻辑操作。
# 计算文件中大于平均值的数的个数 awk '{ sum += $1;v[$1]++} END { avg = sum / NR; for(i in v) if(i>avg) count++; print count,sum,avg }' numbers.txt
-
使用函数:除了内置函数,Awk还可以定义自定义函数,以便重复使用特定的操作。
-
将字符串反转并返回
function reverse_str(str) { result = "" for (i = length(str); i > 0; i--) result = result substr(str, i, 1) return result } # 逐行处理 { reversed = reverse_str($0) print reversed } # 执行 awk -f reverse_str.awk passwd.txt
-
字符串拆分为数组元素
function split_str(str,array,sep) { return split(str,array,sep) } # 逐行处理 { split_str($0,array,":") print array[2] } # 执行 awk -f split_str.awk passwd.txt
-
awk格式化输出printf
%s: 字符占位符 %d: 数字占位符 %.2f: 小数占位符 %-s : 左对齐 %+s : 右对齐
-
案例
awk 'BEGIN{FS=":"}{printf "%s\n",$1}' passwd awk 'BEGIN{FS=":"}{printf "%20s" "%20s\n",$1,$7}' passwd awk 'BEGIN{FS=":"}{printf "%-20s" "%-20s\n",$1,$7}' passwd awk 'BEGIN{FS=":"}{printf "%d\n",$3}' passwd
-
求平均数案例
##文本 cat student.txt Allen 90 80 77 85 Joe 88 76 89 92 Rose 76 98 99 100 Jack 89 70 95 80 awk '{total=$2+$3+$4+$5;Avg=total/4}{printf "%-10s%-8d%-8d%-8d%-8d%-0.2f\n",$1,$2,$3,$4,$5,Avg}' student.txt awk 'BEGIN{printf "%-10s%-8s%-8s%-8s%-8s%-8s\n","Name","Math","English","Chinese","Physical","Avg"}{total=$2+$3+$4+$5;Avg=total/4}{printf "%-10s%-8d%-8d%-8d%-8d%-0.2f\n",$1,$2,$3,$4,$5,Avg}' student.txt
awk条件语句
- 打印passwd文件第3列大于50小于100的值
awk 'BEGIN{FS=":"}{if($3>50 && $3<100) print $0}' /etc/passwd
- awk文件形式
# script.awk BEGIN{ FS=":" } { if($3<50) { printf "%-28s%-25s%-5d\n","小于50的uid",$1,$3 } else if($3>50 && $3<100) { printf "%-25s%-25s%-5d\n","大于50且小于100的uid",$1,$3 } else { printf "%-28s%-25s%-5d\n","大于100的uid",$1,$3 } }
- 引用 script.awk
awk -f script.awk /etc/passwd
awk循环语句
-
while 循环
# cat while.awk BEGIN{ while(i<=100) { sum+=i i++ } print sum }
-
do while 循环
# 语法 do { 动作 }while(条件表达式) # do_while.awk BEGIN{ do { sum+=i i++ }while(i<=100) print sum }
-
for 循环
# 语法 for(i=0;i<=100;i++) { 动作 } # for.awk BEGIN{ for(i=0;i<=100;i++) { sum+=i } print sum }
-
awk案例
需求:给表格添加表头,并新增Avg列,打印平均成绩>85的列,求出满足条件的成绩和
cat> student.txt<<EOF Allen 90 80 77 85 Joe 88 76 89 92 Rose 76 98 99 100 Jack 89 70 95 80 EOF
BEGIN{ printf "%-10s%-10s%-10s%-10s%-10s%-10s\n","Name","Math","English","Chinese","Physical","Avg" } { total=$2+$3+$4+$5 Avg=total/4 if(Avg>85) { printf "%-10s%-10d%-10d%-10d%-10d%-0.2f\n",$1,$2,$3,$4,$5,Avg # 每遍历一行保留一个值 score_math+=$2 score_english+=$3 score_chinese+=$4 score_physical+=$5 } } END{ printf "%-10s%-10d%-10d%-10d%-10d\n","",score_math,score_english,score_chinese,score_physical } # 输出 Name Math English Chinese Physical Avg Joe 88 76 89 92 86.25 Rose 76 98 99 100 93.25 164 174 188 192
字符串函数
-
内置
length(str): 计算长度 index(str1,str2): 返回在str1中查询到的str2的位置 tolower(str): 小写转换 toupper(str): 大写转换 split(str,arr,fs): 分隔字符串,并保存到数组中 match(str,RE): 返回正则表达式匹配到的子串的位置 substr(str,m,n): 截取子串,从m个字符开始,截取n位。n若不指定,则默 sub(RE,RepStr,str): 替换查找到的第一个子串 gsub(RERepStr,str): 替换查找到的所有子串
-
以:为分隔符,返回/etc/passwd中每行中每个字段的长度
# simple_1.twk BEGIN{ FS=":" } { i=1 while(i<=NF) { if(i==NF) printf "%d",length($i) else printf "%d:",length($i) i++ } print "" }
-
搜索字符串"I have a dream"中出现"ea"字符串的位置
awk 'BEGIN{str="I have a dream";location=index(str,"ea");print location}'
-
将字符串"Hadoop is a bigdata Framawork"全部转换为小写
awk 'BEGIN{str="Hadoop is a bigdata Framawork";low_str=tolower(str);print low_str}'
-
将字符串"Hadoop is a bigdata Framawork"全部转换为大写
awk 'BEGIN{str="Hadoop is a bigdata Framawork";up_str=toupper(str);print up_str}'
-
将字符串"Hadoop Kafka Spark Storm HDFS YARN Zokeeper",按照空格为分隔符,分隔每部分保存到数组中
awk 'BEGIN{str="Hadoop Kafka Spark Storm HDFS YARN Zokeeper";split(str,arr," ");for(a in arr) print arr[a]}'
-
搜索字符串"Tranction 2345 Start:Select*from master"第一个数字出现的位置
awk 'BEGIN{str="Tranction 2345 Start:Select*from master";location=match(str,/[0-9]/);print location}'
-
截取字符串"transaction start"的子串,截取条件从第4个字符开始,截取5位
awk 'BEGIN{str="transaction start";print substr(str,4,5)}'
-
替换字符串"Tranction 243 Start,EventID:9002"中第一个匹配到的数字串为$符号
awk 'BEGIN{str="Tranction 243 Start,EventID:9002";sub(/[0-9]+/,"$",str);print str}'