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 - 强大的文本处理语言