1.命令作用
模式扫描和处理语言(pattern scanning and processing language);awk是一种编程语言,用于在linux/unix下对文本和数据进行处理,本质是对满足条件的行数据进行处理(也可以处理其中某个列,或者某几个列)
2.命令语法
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
3.参数详解
OPTIONS:
POSIX options: , GNU long options: (standard)
- -f progfile, --file=progfile,从文本中加载脚本
- -F fs, --field-separator=fs,字段/域分隔符
- -v var=val, --assign=var=val,自定义变量
Short options: , GNU long options: (extensions)
- -b, --characters-as-bytes,以字节数方式处理,如统计行字符数时,-b对中文处理明显不通
- -c, --traditional,
- -C, --copyright,打印版权信息
- -d[file], --dump-variables[=file],执行过程中使用的全局变量(包括内置变量和用户定义变量)导出到指定文件中
- -e 'program-text', --source='program-text',指定多个指令执行
- -E file, --exec=file,与 -f 类似,但具有更强的安全性和隔离性
- -g, --gen-pot,
- -h, --help,打印帮助信息
- -L [fatal], --lint[=fatal]
- -n, --non-decimal-data,awk默认情况下,0x开头的是16进制,0开头的是8进制,-n无效果,如awk 'BEGIN{print 0x123}'
- -N, --use-lc-numeric
- -O, --optimize,启动内部优化机制
- -p[file], --profile[=file],将执行内容输出到文件,后续可直接使用awk -f file执行,如不指定文件名称,则输出到awkprof.out
- -P, --posix,以posix标准模式运行
- -r, --re-interval,启用正则表达式中的区间表达式{m,n}支持
- -S, --sandbox,启用沙盒模式,正常模式下允许文件操作,沙盒模式下文件操作会报错
- -t, --lint-old,检测脚本中的兼容性问题
- -V, --version,打印版本信息
4.参数用例
4.1.指定awk脚本文件执行,对某列进行求和
[root@node1 ~]# free | grep -v total
Mem: 3861520 462908 2942300 15712 456312 3080864
Swap: 4064252 0 4064252
[root@node1 ~]# cat calc.awk
BEGIN { sum=0 }
{ sum+=$2 }
END { print "总和:", sum }
[root@node1 ~]# free | grep -v total | awk -f calc.awk
总和: 7925772
[root@node1 ~]#
[root@node1 ~]# free | grep -v total | awk -E calc.awk
总和: 7925772
[root@node1 ~]#
4.2.自定义分隔符,默认为空格或者tab
[root@node1 ~]# cat test.txt
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
sync:x:5:0:sync:/sbin:/bin/sync
[root@node1 ~]#
[root@node1 ~]# awk -F':' '{print $1}' test.txt
root
bin
daemon
adm
lp
sync
[root@node1 ~]#
4.3.自定义变量
[root@node1 ~]# awk -F ':' -v n=10 '{print $3+n}' test.txt # 打印文件中第三列加上变量n的结果
10
11
12
13
14
15
[root@node1 ~]#
4.4.以字节数进行处理,中文处理时默认时字符数统计,添加-b以字节数进行处理
[root@node1 ~]# cat test1.txt
好好学习天天向上
this is a cat;
[root@node1 ~]# awk -b '{print length($0)}' test1.txt
24
14
[root@node1 ~]# awk '{print length($0)}' test1.txt
8
14
[root@node1 ~]#
4.5.执行变量导出到指定文件中
[root@node1 ~]# awk -ddump.txt -F ':' '{sum+=$3} END{print sum}' test.txt
15
[root@node1 ~]# cat dump.txt
ARGC: 2
ARGIND: 1
ARGV: array, 2 elements
BINMODE: 0
CONVFMT: "%.6g"
ERRNO: ""
FIELDWIDTHS: ""
FILENAME: "test.txt"
FNR: 6
FPAT: "[^[:space:]]+"
FS: ":"
IGNORECASE: 0
LINT: 0
NF: 7
NR: 6
OFMT: "%.6g"
OFS: " "
ORS: "\n"
RLENGTH: 0
RS: "\n"
RSTART: 0
RT: "\n"
SUBSEP: "\034"
TEXTDOMAIN: "messages"
sum: 15
[root@node1 ~]#
4.6.指定多个可执行命令
[root@node1 ~]# awk -F ':' -e 'BEGIN{print "Start"}' -e '{print $3}' test.txt # 先打印 "Start",再输出 data.txt 每行的第一列
Start
0
1
2
3
4
5
[root@node1 ~]#
[root@node1 ~]# awk -F ':' -e '{print $1}' -e '{print $3}' test.txt # 打印多个列交叉输出
root
0
bin
1
daemon
2
adm
3
lp
4
sync
5
[root@node1 ~]#
[root@node1 ~]# awk --source='BEGIN{FS=":"}' --source='{print $5}' test.txt
root
bin
daemon
adm
lp
sync
[root@node1 ~]#
4.7.启动awk内部优化
[root@node1 ~]# cat test2.txt
123
456
789
101
112
131
415
[root@node1 ~]# time awk '{for(i=1;i<=10000000;i++) sum+=$1} END{print sum}' test2.txt # 未优化
21270000000
real 0m9.824s
user 0m9.812s
sys 0m0.011s
[root@node1 ~]# time awk -O '{for(i=1;i<=10000000;i++) sum+=$1} END{print sum}' test2.txt # 启动优化
21270000000
real 0m9.683s
user 0m9.676s
sys 0m0.006s
[root@node1 ~]#
4.8.将执行内容输出到文件,后续可直接使用awk -f file执行
[root@node1 ~]# awk --profile 'BEGIN{for(i=1;i<=1000;i++) print i}' # 将awk执行内容输出到文件,不指定文件名称默认输出到awkprof.out
1
... ...
1000
[root@node1 ~]# cat awkprof.out
# gawk profile, created Fri Jun 6 03:26:51 2025
# BEGIN block(s)
BEGIN {
for (i = 1; i <= 1000; i++) {
print i
}
}
[root@node1 ~]# awk --profile=awkprof.awk 'BEGIN{for(i=1;i<=1000;i++) print i}' # 指定输出文件
4.9.以posix标准模式运行
[root@node1 ~]# awk 'BEGIN{print 2**3}'
8
[root@node1 ~]# awk --posix 'BEGIN{print 2^3}'
8
[root@node1 ~]# awk 'BEGIN{print 2^3}'
8
[root@node1 ~]# awk --posix 'BEGIN{print 2**3}'
awk: cmd. line:1: BEGIN{print 2**3}
awk: cmd. line:1: ^ syntax error
[root@node1 ~]#
4.10.启用正则表达式中的区间表达式{m,n}支持
[root@node1 ~]# cat test3.txt
this is a cat
is good
Never give up
gooood
good
gived
uping
going
[root@node1 ~]# awk '/go{2,5}d/{print}' test3.txt
is good
gooood
good
[root@node1 ~]# awk -r '/go{2,5}d/{print}' test3.txt
is good
gooood
good
[root@node1 ~]#
4.11.启用沙盒模式,正常模式下允许文件操作,沙盒模式下文件操作会报错
[root@node1 ~]# awk '{print $0 > "output.txt"}' test.txt
[root@node1 ~]# cat output.txt
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
sync:x:5:0:sync:/sbin:/bin/sync
[root@node1 ~]# awk -S '{print $0 > "output1.txt"}' test.txt
awk: cmd. line:1: (FILENAME=test.txt FNR=1) fatal: redirection not allowed in sandbox mode
[root@node1 ~]#
5.其他用例
5.1.打印出第3列
[root@node1 ~]# ps aux | awk '{print $3}' | head -n 5
%CPU
0.0
0.0
0.0
0.0
[root@node1 ~]#
5.2.按照':'作为分隔符,打印第2,第3列
[root@node1 ~]# awk -F ':' '{print $2,$3}' test.txt
x 0
x 1
x 2
x 3
x 4
x 5
[root@node1 ~]#
5.3.打印最后一列,打印总列数
# NF 是列的数量,$NF即为最后一行,该文件:分隔共7列,$NF与$7效果一样
# NF: number of filed
[root@node1 ~]# awk -F ':' '{print $NF}' test.txt
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
[root@node1 ~]#
[root@node1 ~]# awk -F ':' '{print NF}' test.txt | tail -n1 # 打印总列数
7
[root@node1 ~]#
5.4.打印指定行第5行,打印总行数
# NR: number of row
[root@node1 ~]# awk '{if(NR==5) print}' test.txt # 打印第5行
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@node1 ~]#
[root@node1 ~]# awk '{print NR}' test.txt | tail -n 1 # 打印行数
6
[root@node1 ~]#
5.5.指定分隔符,打印第2、3、4列,打印的列分隔符与原分隔符一样
# OFS: output field separator,输出的分隔符,不指定默认为空格
# FS: field separator,即-F指定的内容
# OFS=FS: 即输出的分隔符为-F指定的内容
[root@node1 ~]# awk -F ':' '{OFS=FS; print $2,$3,$4}' test.txt
x:0:0
x:1:1
x:2:2
x:3:4
x:4:7
x:5:0
[root@node1 ~]#
5.6.指定分隔符,将第2列全部改xxxx字符串
[root@node1 ~]# awk -F ':' '{OFS=FS;$2="xxxx";print}' test.txt
root:xxxx:0:0:root:/root:/bin/bash
bin:xxxx:1:1:bin:/bin:/sbin/nologin
daemon:xxxx:2:2:daemon:/sbin:/sbin/nologin
adm:xxxx:3:4:adm:/var/adm:/sbin/nologin
lp:xxxx:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:xxxx:5:0:sync:/sbin:/bin/sync
[root@node1 ~]#
5.7.指定分隔符,将第2-4行的第2列改成xxxx
[root@node1 ~]# awk -F ':' '{if(NR >=2 && NR <=4) $2="xxxx";OFS=FS;print}' test.txt
root:x:0:0:root:/root:/bin/bash
bin:xxxx:1:1:bin:/bin:/sbin/nologin
daemon:xxxx:2:2:daemon:/sbin:/sbin/nologin
adm:xxxx:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
[root@node1 ~]#
5.8.指定分隔符,打印第7列匹配'bash'关键字的行
# 匹配为~ ,不匹配为!~
[root@node1 ~]# awk -F ':' '{if($7 ~ /bash/) print}' test.txt
root:x:0:0:root:/root:/bin/bash
[root@node1 ~]#
5.9.打印第一列,且每行前添加指定字符
[root@node1 ~]# awk -F ':' -v 'a=xx' '{print a,$1}' test.txt
xx root
xx bin
xx daemon
xx adm
xx lp
xx sync
[root@node1 ~]#
5.10.指定分隔符,取出第7列中第4个字符开始往后取5个字符
[root@node1 ~]# awk -F ':' '{print substr($7,4,5)}' test.txt
n/bas
in/no
in/no
in/no
in/no
n/syn
[root@node1 ~]#
5.11.指定分隔符,替换第7列中的sbin为TTTT
推广至满足某些条件的行当中的某些列进行处理;
注:awk中字符串等请使用双引号;
[root@node1 ~]# awk -F ':' '$7 ~ /sbin/ {OFS=FS;gsub("sbin","TTTT",$7);print}' test.txt
bin:x:1:1:bin:/bin:/TTTT/nologin
daemon:x:2:2:daemon:/sbin:/TTTT/nologin
adm:x:3:4:adm:/var/adm:/TTTT/nologin
lp:x:4:7:lp:/var/spool/lpd:/TTTT/nologin
[root@node1 ~]#
5.12.取出日志中时间在2024年9月11日10点0分到10点10分的日志
# 日期后面是' CST',以此为分隔符,$1则为时间列
awk -F ' CST' '{if ($1 >= "2024-09-11 10:00:00" && $1 <= "2024-09-11 10:10:00") print}' test.csv
# sed -n '/开始时间/,/结束时间/p' xxx.log
# 注:必须保证匹配的"开始时间"和"结束时间"内容在日志文件中都存在,如果不存在,将取不到数据
sed -n '/2024-09-11 10:00:00/,/2024-09-11 10:10:00/p' test.csv
5.13.将第2到5行数据的第3列求和
[root@node1 ~]# awk -F ':' 'BEGIN {sum=0} {if(NR>=2 && NR<=4) sum=sum+$3} END {print sum}' test.txt
6
[root@node1 ~]#
注:不管有没有BEGIN或者END,书写格式中都需要有{}作为前后结尾;但如果是匹配,则略有不同:
[root@node1 ~]# awk -F ':' '$7 ~ /sbin/ {OFS=FS;gsub("sbin","TTTT",$7);print}' test.txt
bin:x:1:1:bin:/bin:/TTTT/nologin
daemon:x:2:2:daemon:/sbin:/TTTT/nologin
adm:x:3:4:adm:/var/adm:/TTTT/nologin
lp:x:4:7:lp:/var/spool/lpd:/TTTT/nologin
[root@node1 ~]# awk -F ':' '{if($7 ~ /sbin/) {OFS=FS;gsub("sbin","TTTT",$7);print}}' test.txt
bin:x:1:1:bin:/bin:/TTTT/nologin
daemon:x:2:2:daemon:/sbin:/TTTT/nologin
adm:x:3:4:adm:/var/adm:/TTTT/nologin
lp:x:4:7:lp:/var/spool/lpd:/TTTT/nologin
[root@node1 ~]#
5.14.用户下cpu内存使用量
1)ps aux | awk 'BEGIN {cpusum=0;memsum=0} $1 ~/clouder|hdfs/ {cpusum=cpusum+$3; memsum=memsum+$4}; END {print cpusum,memsum}'
2)cpusum=0;for i in `ps aux | awk ‘$1 ~/clouder|hdfs/ {print $3}’`; do cpusum=$(($cpusum+$i)) ;done;echo $cpusum (注:shell中浮点数相加不能直接$(($cpusum+$i)),需要另寻办法)
3)a=0;for i in `ps aux | awk '$1 ~/clouder|hdfs/ {print $3}'`; do a=`echo "$a+$i"|bc` ;done;echo $a
5.15.Length字符串函数的使用
5.15.1.打印出每行的总长度
[root@node1 ~]# awk '{print length}' test.txt
31
32
39
36
40
31
[root@node1 ~]#
5.15.2.打印出第7列长度
[root@node1 ~]# awk -F ':' '{print length($7)}' test.txt
9
13
13
13
13
9
[root@node1 ~]#
5.15.3.打印所有列,且统计每行总长度
[root@node1 ~]# awk -F ':' '{print($0),length}' test.txt
root:x:0:0:root:/root:/bin/bash 31
bin:x:1:1:bin:/bin:/sbin/nologin 32
daemon:x:2:2:daemon:/sbin:/sbin/nologin 39
adm:x:3:4:adm:/var/adm:/sbin/nologin 36
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 40
sync:x:5:0:sync:/sbin:/bin/sync 31
[root@node1 ~]#
5.15.4.打印第二列,且统计第二列的长度
[root@node1 ~]# awk -F ':' '{print($5),length($5)}' test.txt
root 4
bin 3
daemon 6
adm 3
lp 2
sync 4
[root@node1 ~]#
5.16.其他
# 开始定义sum=0
# $1第一列不存在#号的行,计算第二列的和
# 当和大于86时,输出第一列,求和,然后将sum置为0
# 依次循环处理
# 可以考虑最后sum不满86,是不是会不输出,可以生成数字进行测试
awk 'BEGIN {sum = 0}; $1 !~ /#/ {sum=sum+$2;if (sum >86) {print $1,sum;sum=0 }}' text.log
text.log内容如
# this is number one
1 12
2 23
3 22
4 8
5 7
6 14
. .
. .
. .