当前位置:首页>Linux>Linux 命令行 awk 高级用法大全

Linux 命令行 awk 高级用法大全

  • 2026-09-02 17:12:54
Linux 命令行 awk 高级用法大全

Linux awk 高级用法大全

一、基础核心原理

1. 执行流程

BEGIN{ 预处理 }
# 逐行处理文本
pattern{ action }
END{ 收尾汇总 }
  • • $0:整行文本;$1/$2/$n:第1/2/n列
  • • NF:当前行总列数;NR:当前行号;FNR:多文件各自行号
  • • FS:输入分隔符;OFS:输出分隔符;RS:行分隔符;ORS:输出行分隔符

2. 内置变量速查表

变量
含义
NR
所有文件累计行号
FNR
当前文件独立行号
NF
当前行列总数,$NF=最后一列
FS
字段分隔符,默认空格
OFS
输出字段分隔符,默认空格
RS
输入行分隔符,默认换行\n
ORS
输出行分隔符,默认换行\n
FILENAME
当前文件名
ARGC/ARGV
参数个数/参数数组

二、分隔符高级用法

1. 指定单分隔符

# -F 指定分隔符,冒号分割 /etc/passwd
awk -F: '{print $1,$7}' /etc/passwd
# OFS 修改输出分隔符为 |

awk -F: 'BEGIN{OFS="|"}{print $1,$3}' /etc/passwd

2. 多分隔符(正则分割)

# 分隔符:空格、逗号、横杠 任意一个
awk -F '[ ,-]' '{print $1,$2}' test.txt
# 连续多个分隔符视为一个

awk -F '[: ]+' '{print $1}' test.txt

3. 动态修改分隔符(运行时切换FS)

# 前10行逗号分割,10行后空格分割
awk 'NR<=10{FS=","}NR>10{FS=" "}{print $1}' test.txt

4. 自定义行分隔符 RS(多行读取)

# 空行分隔段落,按段落处理文本
awk -v RS="" '{print "段落:"$0}' test.txt
# 以##
#作为行结束符
awk -v RS="###" '{print $0}' test.txt

三、条件匹配(pattern 高级过滤)

1. 数值比较

# 第三列大于100
awk '$3 > 100' test.txt
# 第2列等于字符串

awk '$2 == "error"' log.txt
# 不等于、小于等于

awk '$4 != 0 && $5 <= 50' test.txt

2. 正则匹配 / !

# 包含ERROR的行
awk '/ERROR/' app.log
# 第5列匹配数字

awk '$5 ~ /^[0-9]+$/' test.txt
# 不包含timeout

awk '! /timeout/' nacos.log
# 忽略大小写匹配

awk 'BEGIN{IGNORECASE=1}/grpc/' log.txt

3. 行号范围匹配

# 第10~100行
awk 'NR>=10 && NR<=100' test.txt
# 匹配start到end之间所有行

awk '/start/,/end/' log.txt

4. 复合多条件 && || !

# 包含ERROR 且 第6列超时大于3000
awk '/ERROR/ && $7>3000' nacos.log
# 包含Timeout 或者 Connection

awk '/Timeout/ || /Connection/' app.log

四、循环、判断、流程控制

1. if / else if / else

awk '{
    if($3 > 1000){
        print $1,"高负载"
    }else if($3>500){
        print $1,"中等负载"
    }else{
        print $1,"正常"
    }
}'
 test.txt

2. for 循环(遍历列、遍历数组)

# 打印每行所有字段
awk '{for(i=1;i<=NF;i++) print $i}' test.txt
# 遍历数组key

awk '{arr[$1]=$2}END{for(k in arr) print k,arr[k]}' test.txt

3. while / do while

# 循环输出每行前3列
awk '{i=1;while(i<=3){print $i;i++}}' test.txt

4. break / continue / next / exit

# next:跳过当前行,直接处理下一行
awk '$1=="skip"{next}{print $0}' test.txt
# break 跳出循环

awk '{for(i=1;i<=NF;i++) if($i=="end") break; print $i}' test.txt
# exit 直接结束程序(END仍会执行)

awk 'NR>100{exit}' test.txt

五、数组高级用法(统计、分组、去重)

awk 数组是关联数组,key可以数字/字符串,核心用于日志统计。

1. 分组计数(统计Nacos报错频次)

# 统计每个IP出现ERROR次数
awk '/ERROR/ && $9~/172.18/{ip=$9; cnt[ip]++}END{for(ip in cnt) print ip,cnt[ip]}' nacos.log

2. 去重、唯一值提取

# 提取不重复的IP
awk '{ip[$9]=1}END{for(i in ip) print i}' log.txt

3. 求和、平均值、最大最小值

# 统计第三列总和、平均值
awk '{sum+=$3; num++}END{print "总和="sum,"平均="sum/num}' test.txt
# 求最大值

awk '{if($3>max) max=$3}END{print "最大值:"max}' test.txt

4. 二维数组模拟

# key:ip+status 分组统计
awk '{key=$9"_"$7; arr[key]++}END{for(k in arr) print k,arr[k]}' log.txt

5. 删除数组元素 delete

awk '{arr[$1]=$2}END{delete arr["127.0.0.1"];for(k in arr)print k}' test.txt

六、BEGIN / END 预处理与汇总高级场景

1. BEGIN 打印表头、设置变量

awk 'BEGIN{
    FS=":";OFS="\t"
    print "用户名","UID","Shell"
}{print $1,$3,$7}'
 /etc/passwd

2. END 汇总输出、排序

# 统计日志等级数量
awk '/ERROR|WARN|INFO/{level=$1;count[level]++}END{
    print "日志统计:"
    print "ERROR:",count["ERROR"]+0
    print "WARN:",count["WARN"]+0
    print "INFO:",count["INFO"]+0
}'
 app.log

3. BEGIN 读取外部变量 -v

# -v 传外部shell变量到awk
search="Timeout"
awk -v key="$search" '$0 ~ key' nacos.log
# 传递数字

threshold=3000
awk -v t="$threshold" '$7 > t' log.txt

七、格式化输出 printf(高级排版)

比print更灵活,支持对齐、数字格式化:

# %s字符串 %d整数 %f浮点数 左对齐- 宽度10
awk '{printf "IP:%-15s 耗时:%6d ms\n",$9,$7}' nacos.log
# 保留2位小数

awk '{printf "平均值:%.2f\n",$3/1000}' test.txt
# 十六进制输出

awk '{printf "UID 十六进制:%x\n",$3}' /etc/passwd

八、多文件处理(FNR / NR 区分文件)

1. 两个文件匹配 join(类似数据库联表)

file1:ip name
file2:ip cost

# 先缓存第一个文件,第二个文件匹配输出
awk 'NR==FNR{map[$1]=$2;next}{print $1,map[$1],$2}' file1 file2

2. 分别统计每个文件行数

awk '{file[FILENAME]++}END{for(f in file) print f,file[f]}' a.txt b.txt

3. 判断当前文件名

awk 'FILENAME=="passwd"{print $1}FILENAME=="group"{print $2}' /etc/passwd /etc/group

九、内置函数大全(字符串/数值/时间)

1. 字符串函数

函数
作用
length($0)
获取字符串长度
sub(/old/,new,$0)
只替换第一个匹配
gsub(/old/,new,$0)
全局替换
index(s,t)
返回t在s中起始下标
substr(s,start,len)
截取子串
split(s,arr,sep)
分割字符串到数组
tolower() / toupper()
大小写转换

示例:

# 全局替换端口9848为9849
awk '{gsub("9848","9849");print $0}' nacos.log
# 截取IP前3段

awk '{ip=substr($9,1,index($9,".")+3);print ip}' log.txt
# 分割字符串

echo
 "172.18.2.184" | awk '{split($0,arr,".");print arr[1],arr[2]}'

2. 数学函数

int(x)   # 取整
sqrt(x)  # 开平方
rand()   # 0~1随机数
srand()  # 设置随机种子
log() exp() sin() cos()

3. 时间函数(gawk专属)

# 时间戳转日期
awk 'BEGIN{print strftime("%Y-%m-%d %H:%M:%S",systime())}'
# 格式化日志时间

awk '{t=$1" "$2;print strftime("%H:%M",mktime("2026 "t))}' log.txt

十、正则高级匹配(分组、转义)

  1. 1. 捕获分组 ()
# 提取172.18开头IP
awk 'match($0,/(172\.18\.[0-9]+\.[0-9]+)/,arr){print arr[1]}' nacos.log
  1. 2. match() 函数捕获正则分组到数组
  2. 3. 转义 . * + ? | () 需加反斜杠 \.

十一、实战高级案例(运维高频)

案例1:Nacos日志统计超时请求

# 统计3000ms以上超时IP及次数
awk '/TimeoutException/ && match($0,/172\.18\.[0-9.]+/,ip){
    cnt[ip[0]]++
}END{
    printf "%-15s %s\n","IP","超时次数"
    for(k in cnt) printf "%-15s %d\n",k,cnt[k]
}'
 nacos-raft.log

案例2:过滤Jstack阻塞线程,统计线程池

awk '"Thread" in $0{name=$0;next}/WAITING|BLOCKED/{arr[name]++}END{for(t in arr) print arr[t],t}' jstack.log

案例3:清理日志,只保留ERROR行并格式化输出

awk 'BEGIN{OFS=" | "}
/ERROR/{
    gsub(/[0-9]{2}:[0-9]{2}:[0-9]{2}/,"TIME",$0)
    print $1,$2,$9,$NF
}'
 app.log > error-filter.log

案例4:计算磁盘占用总和(df -h 统计)

df -h | awk 'NR>1{gsub(/G/,"",$3);sum+=$3}END{print "总使用G:",sum}'

案例5:去重并统计访问量(nginx日志)

awk '{ip=$1;visits[ip]++}END{
    print "访问TOP10:"
    for(i in visits) print visits[i],i
}'
 access.log | sort -nr | head -10

案例6:多行合并(把相同IP的行合并输出)

awk '{lines[$1] = lines[$1] " " $0}END{for(k in lines) print k,lines[k]}' log.txt

十二、性能优化 & 避坑点

  1. 1. 优先用next:多文件处理减少重复判断
    awk 'NR==FNR{map[$1]=$2;next}{...}' f1 f2
  2. 2. 大量日志避免 gsub 频繁全局替换,能用match就不用gsub
  3. 3. 数组key尽量短,减少内存占用
  4. 4. 区分 == 字符串相等、= 赋值,写条件不要写错
  5. 5. 原生awk不支持strftime,必须使用 gawk(CentOS默认awk是gawk)
  6. 6. $NF 最后一列;$(NF-1) 倒数第二列
  7. 7. 空数组取值 arr[key]+0 防止空输出

十三、awk 一行常用速查

# 打印最后一列
awk '{print $NF}'
# 打印倒数第二列

awk '{print $(NF-1)}'
# 打印行号+内容

awk '{print NR,$0}'
# 过滤空行

awk 'NF>0'
# 删除重复行(保留首次出现)

awk '!seen[$0]++'
# 统计总行数

awk 'END{print NR}'
# 字段包含数字

awk '$1 ~ /[0-9]/'
# 输出不重复字段

awk '{u[$1]}END{for(i in u)print i}'

最新文章

随机文章