Linux Shell awk
awk 是一个功能强大的文本处理工具,它不仅是 Linux 命令,更是一门专门的编程语言。
它特别擅长处理结构化文本数据(如日志、CSV文件等),
能够进行逐行扫描、字段分割、模式匹配和数据操作。
一、awk 基本概念和工作原理
1. 工作原理
awk 的基本工作流程是:逐行扫描文件,从第一行到最后一行。对于每一行,它会检查是否匹配指定的“模式”,如果匹配,则执行对应的“动作”。
2. 基本语法
awk '模式 { 动作 }' 输入文件
模式:可以是正则表达式、条件表达式(如 NR > 10)、特殊模式(BEGIN 或 END),或者完全省略(表示处理所有行)。
动作:是一系列用花括号 {} 括起来的命令,通常是 print 语句,多个命令之间用分号 ; 分隔。
输入文件:要处理的文本文件。如果不指定,则从标准输入读取
3. 内置变量
awk 预定义了许多有用的变量,无需声明即可使用。
变量名    含义
$0    当前行的全部内容
$1, $2, ... $n    当前行的第1个、第2个...第n个字段
NF    Number of Fields,当前行的字段总数
NR    Number of Records,当前的行号(对所有文件累计)
FNR    File Number of Records,当前文件中的行号
FS    Field Separator,输入字段分隔符(默认为空格/制表符)
OFS    Output Field Separator,输出字段分隔符(默认为空格)
RS    Record Separator,输入记录(行)分隔符(默认为换行符)
ORS    Output Record Separator,输出记录(行)分隔符(默认为换行符)
FILENAME    当前正在处理的文件名
二、awk 使用案例
假设我们有一个名为 students.txt 的文件,内容如下:
Alice Johnson 95 88 92
Bob Smith 78 85 80
Carol Davis 88 91 89
David Miller 65 70 75
案例1:基本打印
打印整个文件:
awk '{print}' students.txt
# 或
awk '{print $0}' students.txt
打印第一列(姓名):
awk '{print $1}' students.txt
[root@hadoop ~]# awk '{print $1}' students.txt
Alice
Bob
Carol
David
打印第一列和第三列:
[root@hadoop ~]# awk '{print $1, $3}' students.txt
Alice 95
Bob 78
Carol 88
David 65
案例2:使用 NF 和 NR
打印每一行的最后一个字段:
awk '{print $NF}' students.txt
# 输出:92 80 89 75
打印行号和该行的内容:
awk '{print NR, $0}' students.txt
[root@hadoop ~]# awk '{print NR, $0}' students.txt
1 Alice Johnson 95 88 92
2 Bob Smith 78 85 80
3 Carol Davis 88 91 89
4 David Miller 65 70 75
打印文件总行数:打印文件总行数:
[root@hadoop ~]# awk 'END {print NR}' students.txt
4
案例3:模式匹配(过滤)
打印包含 "Bob" 的行:
[root@hadoop ~]# awk '/Bob/ {print $0}' students.txt
Bob Smith 78 85 80
打印第二门课成绩大于90的行:
[root@hadoop ~]# awk '$4 > 90 {print $1, $4}' students.txt
Carol 91
打印第一门课成绩在80到100之间的行:
awk '$3 >= 80 && $3 <= 100 {print $0}' students.txt
[root@hadoop ~]# awk '$3 >= 80 && $3 <= 100 {print $0}' students.txt
Alice Johnson 95 88 92
Carol Davis 88 91 89
案例4:使用 BEGIN 和 END
BEGIN 和 END 是特殊的模式,分别在处理第一行之前和处理完最后一行之后执行。
添加表头:
[root@hadoop ~]# awk 'BEGIN {print "Name\tScore1\tScore2\tScore3"; print "----------------------"}
>      {print $1, $3, $4, $5}
>      END {print "----------------------\nProcessing complete."}' students.txt
Name    Score1  Score2  Score3
----------------------
Alice 95 88 92
Bob 78 85 80
Carol 88 91 89
David 65 70 75
----------------------
Processing complete.
案例5:字段分隔符
处理 CSV 文件(逗号分隔)
假设有 data.csv:
John,Doe,30
Jane,Smith,25
awk -F, '{print $1, $3}' data.csv
# -F, 指定输入字段分隔符为逗号
# 输出:
# John 30
# Jane 25
[root@hadoop ~]# awk -F, '{print $1, $3}' data.csv
John 30
Jane 25
同时指定输入和输出分隔符:
awk 'BEGIN {FS=" "; OFS=" - "} {print $1, $NF}' students.txt
[root@hadoop ~]# awk 'BEGIN {FS=" "; OFS=" - "} {print $1, $NF}' students.txt
Alice - 92
Bob - 80
Carol - 89
David - 75
案例6:计算和统计
计算每个学生的平均分:
awk '{sum = $3 + $4 + $5; avg = sum / 3; print $1, avg}' students.txt
# 输出:
# Alice 91.6667
# Bob 81
# Carol 89.3333
# David 70
[root@hadoop ~]# awk '{sum = $3 + $4 + $5; avg = sum / 3; print $1, avg}' students.txt
Alice 91.6667
Bob 81
Carol 89.3333
David 70
计算全班第一门课的总分和平均分:
awk '{sum += $3} END {print "Total: " sum, "Average: " sum/NR}' students.txt
# 输出:Total: 326 Average: 81.5
案例7:使用 if-else 语句
awk 也支持完整的编程结构。
给成绩评级:
awk '{
avg = ($3+$4+$5)/3;
if (avg >= 90) grade = "A";
else if (avg >= 80) grade = "B";
else if (avg >= 70) grade = "C";
else grade = "F";
print $1, avg, grade;
}' students.txt
# 输出:
# Alice 91.6667 A
# Bob 81 B
# Carol 89.3333 B
# David 70 C
案例8:字符串操作
连接姓和名:
awk '{name = $1 " " $2; print name}' students.txt
# 输出:
# Alice Johnson
# Bob Smith
# Carol Davis
# David Miller
查找名字长度大于4的学生:
awk 'length($1) > 4 {print $1}' students.txt
[root@hadoop ~]# awk 'length($1) > 4 {print $1}' students.txt
Alice
Carol
David
三、高级用法:awk 脚本
当命令变得复杂时,可以将其写入一个脚本文件(例如 process.awk)。
process.awk 文件内容:
#!/usr/bin/awk -f
# 这是一个awk脚本示例
BEGIN {
print "=== 学生成绩报告 ==="
printf "%-10s %-8s %s\n", "Name", "Average", "Grade"
print "------------------------"
total_sum = 0
}
{
sum = $3 + $4 + $5
avg = sum / 3
total_sum += avg
  if (avg >= 90) grade = "A"
else if (avg >= 80) grade = "B"
else if (avg >= 70) grade = "C"
else grade = "F"
  printf "%-10s %-8.2f %s\n", $1, avg, grade
}
END {
print "------------------------"
printf "全班平均分: %.2f\n", total_sum / NR
}
运行脚本:
bash
awk -f process.awk students.txt
# 或者给脚本文件添加执行权限后直接运行
chmod +x process.awk
./process.awk students.txt
[root@hadoop ~]# awk -f process.awk students.txt
=== 学生成绩报告 ===
Name       Average  Grade
------------------------
Alice      91.67    A
Bob        81.00    B
Carol      89.33    B
David      70.00    C
------------------------
全班平均分: 83.00
