awk 命令详解#
awk 是 Linux 系统中强大的文本处理工具,它是一种编程语言,专门用于文本和数据提取。awk 支持模式匹配、数学运算、字符串处理等高级功能。
入门#
基本用法#
# 打印整行
awk '{print}' filename.txt
# 打印特定字段
awk '{print $1}' filename.txt
# 打印多个字段
awk '{print $1, $3}' filename.txt
# 使用分隔符
awk -F: '{print $1}' /etc/passwd基本语法#
# 基本结构
awk 'pattern {action}' filename.txt
# 打印包含特定模式的行
awk '/pattern/ {print}' filename.txt
# 使用 BEGIN 和 END
awk 'BEGIN {print "Start"} {print} END {print "End"}' filename.txt常用选项#
| 选项 | 说明 |
|---|---|
-F | 指定字段分隔符 |
-v | 定义变量 |
-f | 从文件读取 awk 程序 |
-W | 指定兼容性模式 |
基本示例#
# 打印第1列
awk '{print $1}' filename.txt
# 打印第1和第3列
awk '{print $1, $3}' filename.txt
# 使用冒号作为分隔符
awk -F: '{print $1}' /etc/passwd
# 打印行号
awk '{print NR, $0}' filename.txt中级#
内置变量#
# NR - 行号
awk '{print NR, $0}' filename.txt
# NF - 字段数
awk '{print NF, $0}' filename.txt
# FILENAME - 当前文件名
awk '{print FILENAME, $0}' filename.txt
# FNR - 当前文件中的行号
awk '{print FNR, $0}' filename.txt
# OFS - 输出字段分隔符
awk 'BEGIN {OFS=":"} {print $1, $2}' filename.txt
# ORS - 输出记录分隔符
awk 'BEGIN {ORS="\n\n"} {print $0}' filename.txt模式匹配#
# 匹配特定模式
awk '/pattern/ {print}' filename.txt
# 匹配多个模式
awk '/pattern1/ || /pattern2/ {print}' filename.txt
# 排除特定模式
awk '!/pattern/ {print}' filename.txt
# 字段匹配
awk '$1 == "value" {print}' filename.txt
# 数值比较
awk '$3 > 100 {print}' filename.txt字符串操作#
# 字符串长度
awk '{print length($0)}' filename.txt
# 字符串连接
awk '{print $1 $2}' filename.txt
# 字符串分割
awk '{split($0, a, ":"); print a[1]}' filename.txt
# 字符串替换
awk '{gsub(/old/, "new"); print}' filename.txt
# 大小写转换
awk '{print toupper($1)}' filename.txt
awk '{print tolower($1)}' filename.txt数学运算#
# 基本运算
awk '{print $1 + $2}' filename.txt
awk '{print $1 * $2}' filename.txt
awk '{print $1 / $2}' filename.txt
# 数学函数
awk '{print sqrt($1)}' filename.txt
awk '{print int($1)}' filename.txt
awk '{print rand()}' filename.txt
# 累加
awk '{sum += $1} END {print sum}' filename.txt
# 平均值
awk '{sum += $1; count++} END {print sum/count}' filename.txt高级#
条件语句#
# if 语句
awk '{if ($1 > 100) print $1}' filename.txt
# if-else 语句
awk '{if ($1 > 100) print "High"; else print "Low"}' filename.txt
# 多条件
awk '{if ($1 > 100 && $2 < 50) print $1, $2}' filename.txt
# 嵌套条件
awk '{if ($1 > 100) {if ($2 < 50) print $1, $2}}' filename.txt循环语句#
# for 循环
awk '{for (i=1; i<=NF; i++) print $i}' filename.txt
# while 循环
awk '{i=1; while (i<=NF) {print $i; i++}}' filename.txt
# do-while 循环
awk '{i=1; do {print $i; i++} while (i<=NF)}' filename.txt
# break 和 continue
awk '{for (i=1; i<=NF; i++) {if ($i == "stop") break; print $i}}' filename.txt数组操作#
# 数组赋值
awk '{a[NR] = $0} END {for (i in a) print a[i]}' filename.txt
# 关联数组
awk '{count[$1]++} END {for (i in count) print i, count[i]}' filename.txt
# 数组排序
awk '{a[NR] = $0} END {n = asort(a); for (i=1; i<=n; i++) print a[i]}' filename.txt
# 数组删除
awk '{a[$1] = $2} END {delete a["key"]; for (i in a) print i, a[i]}' filename.txt函数定义#
# 自定义函数
awk 'function add(a, b) {return a + b} {print add($1, $2)}' filename.txt
# 带默认参数的函数
awk 'function greet(name) {return "Hello, " name} {print greet($1)}' filename.txt
# 递归函数
awk 'function factorial(n) {if (n <= 1) return 1; return n * factorial(n-1)} {print factorial($1)}' filename.txt大师#
高级文本处理#
# 统计词频
awk '{for (i=1; i<=NF; i++) words[$i]++} END {for (w in words) print w, words[w]}' filename.txt
# 提取特定格式的数据
awk '/^Date:/ {date=$0} /^Time:/ {time=$0} /^Value:/ {print date, time, $0}' filename.txt
# 多行处理
awk '/START/{flag=1} flag{print} /END/{flag=0}' filename.txt
# 列转行
awk '{for (i=1; i<=NF; i++) print $i}' filename.txt数据分析#
# 计算统计信息
awk '{sum+=$1; sumsq+=$1*$1; count++} END {print "Mean:", sum/count; print "StdDev:", sqrt(sumsq/count - (sum/count)^2)}' filename.txt
# 找最大值和最小值
awk 'NR==1 {max=$1; min=$1} {if ($1>max) max=$1; if ($1<min) min=$1} END {print "Max:", max, "Min:", min}' filename.txt
# 百分位数
awk '{a[NR]=$1} END {n=asort(a); print "Median:", a[int(n/2)]}' filename.txt
# 频率分布
awk '{freq[int($1/10)*10]++} END {for (f in freq) print f"-"f+9, freq[f]}' filename.txt文件处理#
# 读取多个文件
awk 'FNR==1 {print "File:", FILENAME} {print}' file1.txt file2.txt
# 合并文件
awk '{print FILENAME, $0}' file1.txt file2.txt
# 比较文件
awk 'NR==FNR {a[$1]=$2; next} {print $1, a[$1], $2}' file1.txt file2.txt
# 处理CSV文件
awk -F, '{print $1, $3, $5}' data.csv高级脚本#
# 日志分析脚本
#!/bin/bash
LOG_FILE="$1"
echo "Top 10 IP addresses:"
awk '{ip[$1]++} END {for (i in ip) print ip[i], i}' "$LOG_FILE" | sort -rn | head -n 10
echo "Top 10 URLs:"
awk '{url[$7]++} END {for (i in url) print url[i], i}' "$LOG_FILE" | sort -rn | head -n 10
# 数据转换脚本
#!/bin/bash
INPUT="$1"
OUTPUT="$2"
awk -F, '{print $1 "\t" $3 "\t" $5}' "$INPUT" > "$OUTPUT"
# 配置文件解析脚本
#!/bin/bash
CONFIG="$1"
awk -F= '{gsub(/^[ \t]+|[ \t]+$/, "", $1); gsub(/^[ \t]+|[ \t]+$/, "", $2); print $1, $2}' "$CONFIG"无敌#
高级技巧#
# 使用正则表达式
awk '/^[0-9]+$/ {print}' filename.txt
# 多分隔符处理
awk -F'[:,]' '{print $1, $3, $5}' filename.txt
# 动态字段处理
awk '{for (i=1; i<=NF; i++) if ($i ~ /pattern/) print $i}' filename.txt
# 复杂模式匹配
awk '$1 ~ /^pattern/ && $2 > 100 {print}' filename.txt大文件处理#
# 分块处理
awk 'NR%1000000==0 {print "Processing line", NR > "/dev/stderr"} {print}' largefile.txt
# 内存优化
awk '{if (NR%1000==0) {print; next}} {line=$0} END {print line}' largefile.txt
# 并行处理
split -l 1000000 largefile.txt chunk_
for chunk in chunk_*; do
awk '{print $1, $3}' "$chunk" > "$chunk.processed"
done
cat chunk_*.processed > final_result.txt自动化工作流#
# 自动化数据处理
#!/bin/bash
INPUT_DIR="./input"
OUTPUT_DIR="./output"
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.csv; do
filename=$(basename "$file")
awk -F, '{print $1 "\t" $3 "\t" $5}' "$file" > "$OUTPUT_DIR/$filename"
done
# 自动化日志分析
#!/bin/bash
LOG_DIR="/var/log"
REPORT_DIR="./reports"
mkdir -p "$REPORT_DIR"
DATE=$(date +%Y-%m-%d)
find "$LOG_DIR" -name "*$DATE*" -type f | while read log; do
filename=$(basename "$log")
awk '{ip[$1]++} END {for (i in ip) print ip[i], i}' "$log" | sort -rn > "$REPORT_DIR/$filename.stats"
done
# 自动化数据转换
#!/bin/bash
SOURCE_DIR="./source"
TARGET_DIR="./target"
mkdir -p "$TARGET_DIR"
for file in "$SOURCE_DIR"/*.txt; do
filename=$(basename "$file" .txt)
awk '{print $1, $3, $5}' "$file" > "$TARGET_DIR/$filename.csv"
done性能调优#
# 监控性能
time awk '{print $1, $3}' largefile.txt
# 使用 strace 分析
strace -c awk '{print $1, $3}' largefile.txt
# 使用 valgrind 分析内存
valgrind --tool=massif awk '{print $1, $3}' largefile.txt
# 优化处理
awk '{print $1, $3}' largefile.txt | sort -S 1G高级应用场景#
# 数据库数据处理
mysql -u user -p database -e "SELECT * FROM table" | awk -F'\t' '{print $1, $3, $5}'
# 系统监控数据处理
vmstat 1 100 | awk '{print $1, $4, $5}'
# 网络数据处理
tcpdump -i eth0 -n | awk '{print $3, $5}'
# 用户活动数据处理
last | awk '{user[$1]++; login[$1]++} END {for (u in user) print u, user[u], login[u]}'最佳实践#
1. 使用场景#
- 文本和数据提取
- 日志分析
- 数据转换和格式化
- 统计和分析
2. 性能优化#
- 避免在循环中使用复杂操作
- 使用内置变量和函数
- 合理使用 BEGIN 和 END
- 处理大文件时注意内存使用
3. 代码风格#
- 使用有意义的变量名
- 添加注释说明复杂逻辑
- 保持代码简洁
- 使用适当的缩进
4. 脚本集成#
- 在脚本中使用管道组合命令
- 处理错误和异常情况
- 使用变量和参数化脚本
- 添加日志和调试信息
5. 学习路径#
- 先掌握基本语法和变量
- 学习模式匹配和条件语句
- 掌握数组和函数
- 学习高级文本处理
- 最后学习性能优化和自动化
常见问题#
Q: awk 和 sed 有什么区别?#
A: awk 是完整的编程语言,适合复杂的数据处理和分析;sed 是流编辑器,适合文本替换和转换。
Q: 如何处理多字节字符?#
A: 使用 gawk 或 mawk,它们对多字节字符有更好的支持。
Q: 如何在 awk 中使用 shell 变量?#
A: 使用 -v 选项:awk -v var="$shell_var" '{print var}' filename.txt
Q: 如何处理 CSV 文件中的引号?#
A: 使用 FPAT 变量:awk 'FPAT="[^,]*|\"[^\"]+\""' filename.txt
Q: 如何调试 awk 脚本?#
A: 使用 --dump-variables 和 --profile 选项,或者添加 print 语句。
相关命令#
sed- 流编辑器grep- 文本搜索cut- 字段提取sort- 文本排序perl- 强大的文本处理语言