原力注入

AWK 入门教程:强大的文本处理工具

AWK 是一种强大的文本处理工具,广泛用于 Linux/Unix 系统中对文本文件或数据流进行操作。它能够基于条件筛选、统计字段、重新排列数据等。主要特点包括:

  • • 基于模式匹配: 根据条件筛选数据。

  • • 列操作能力: 简单高效地处理文本列数据。

  • • 轻量编程语言: 提供内置变量、循环、条件语句等编程功能。

  • 相关资料

    《AWK 编程语言》:

  • https://github.com/wuzhouhui/awk/blob/twoside/The_AWK_Programming_Language_zh_CN.pdf

2. AWK 的基本语法

2.1 AWK 程序的结构

AWK 程序的结构:

awk 'pattern { action }' file
  • • pattern: 指定操作的匹配规则,例如正则表达式、逻辑判断等。

  • • action: 指满足条件时要执行的操作,用 {} 包围,例如打印、统计、替换等。

  • • file: 要处理的文本文件名称。

2.2 常用内置变量

变量含义
NR当前处理的行号
FNR当前文件的行号(处理多个文件时的相对行号)
NF当前行的字段数(列数)
2第 1 列、第 2 列的值
$NF当前行的最后一列值
FS输入字段分隔符(默认为空格)
OFS输出字段分隔符(默认空格)
RS输入记录分隔符(默认为换行符)
ORS输出记录分隔符(默认为换行符)
ARGIND当前处理的文件在命令行参数中的索引
ARGC命令行参数的数量
ENVIRON存储当前环境变量的关联数组
FILENAME当前正在处理的文件名
SUBSEP数组下标分隔符(默认为 \034)
RSTARTmatch 函数匹配字符串的起始位置
RLENGTHmatch 函数匹配字符串的长度

以下是 常用内置变量 的补充说明,以 Markdown 格式输出:

变量说明:

  1. 1. NR 和 FNR 的区别:

  • • NR:累计行号,处理多个文件时行号会累加。

  • • FNR:当前文件的行号,处理多个文件时每个文件的行号从 1 开始重新计数。

  • 2. FS 和 OFS 的作用:

    • • FS:指定输入字段的分隔符,默认是空格。

    • • OFS:指定输出字段的分隔符,默认是空格。

  • 3. RS 和 ORS 的作用:

    • • RS:指定输入记录的分隔符,默认是换行符。

    • • ORS:指定输出记录的分隔符,默认是换行符。

  • 4. ENVIRON 的使用:

    • • ENVIRON 是一个关联数组,用于访问环境变量。例如:

      awk 'BEGIN { print ENVIRON["HOME"] }'
  • 5. RSTART 和 RLENGTH:

    • • 这两个变量与 match 函数配合使用,用于获取匹配字符串的起始位置和长度。例如:

      awk 'BEGIN { str = "hello world"; match(str, /world/); print RSTART, RLENGTH }'
  • 6. SUBSEP:

    • • 用于多维数组的下标分隔符,默认是 \034(非打印字符)。例如:

      awk 'BEGIN { arr["a", "b"] = 10; print arr["a", "b"] }'
  • 7. ARGIND 和 ARGC:

    • • ARGIND:当前处理的文件在命令行参数中的索引(从 1 开始)。

    • • ARGC:命令行参数的数量。例如:

      awk 'BEGIN { print ARGIND, ARGC }' file1.txt file2.txt
  • 8. FILENAME:

    • • 当前正在处理的文件名。例如:

      awk '{ print FILENAME, $0 }' file1.txt file2.txt
  • 9. 2, ..., $NF:

    • • $1 表示第 1 列,$2 表示第 2 列,依此类推。

    • • $NF 表示当前行的最后一列。

  • 10. NF:

    • • 当前行的字段数(列数)。例如:

      awk '{ print NF }' file.txt
  • 11. RS 和 ORS 的高级用法:

    • • 可以修改 RS 和 ORS 来处理非标准格式的文件。例如,将 RS 设置为空字符串,以处理多行记录:

      awk 'BEGIN { RS = "" } { print $0 }' file.txt
  • 12. SUBSEP 的高级用法:

    • • 可以修改 SUBSEP 来定义多维数组的下标分隔符。例如:

      awk 'BEGIN { SUBSEP = ":"; arr["a", "b"] = 10; print arr["a", "b"] }'
  • 13. RSTART 和 RLENGTH 的高级用法:

    • • 结合 match 函数,可以提取匹配的子字符串。例如:

      awk 'BEGIN { str = "hello world"; match(str, /world/); print substr(str, RSTART, RLENGTH) }'
  • 14. ENVIRON 的高级用法:

    • • 可以遍历 ENVIRON 数组,打印所有环境变量。例如:

      awk 'BEGIN { for (key in ENVIRON) print key, ENVIRON[key] }'
  • 15. FILENAME 的高级用法:

    • • 在处理多个文件时,可以根据文件名执行不同的操作。例如:

      awk '{ if (FILENAME == "file1.txt") print "File1:", $0; else print "File2:", $0 }' file1.txt file2.txt

    2.3 运行 AWK 程序

    AWK 程序可以通过以下方式运行:

    1. 1. 命令行直接运行:

      awk 'pattern { action }' file
    • • pattern:匹配条件(可选)。

    • • action:满足条件时执行的操作。

    • • file:要处理的文件。

  • 2. 脚本文件运行:

    awk -f script.awk file

    示例:假设 script.awk 内容如下:

    { print $1 }

    运行命令:

    awk -f script.awk file.txt
    • • script.awk:包含 AWK 程序的脚本文件。

    • • file:要处理的文件。

    注意事项:

    • • 未指定文件时,AWK 从标准输入读取数据;

    • • 可同时处理多个文件;

    2.4 基本输出

    • • 打印文件的所有内容:

      awk '{ print $0 }' file.txt
    • • 打印文件的第 1 列和第 3 列:

      awk '{ print $1, $3 }' file.txt

    2.5 高级输出

    printf 格式化输出

    printf 可以格式化输出内容,例如:

    awk '{ printf "Name: %s, Age: %d\n", $1, $2 }' file.txt

    排序输出

    结合 sort 命令对输出进行排序:

    awk '{ print $1 }' file.txt | sort

    2.6 选择/过滤行

    按某列的值

    • • 打印第 2 列大于 50 的行:

      awk '$2 > 50 { print }' file.txt

    按某几列值的计算结果

    • • 打印第 1 列和第 2 列之和大于 100 的行:

      awk '$1 + $2 > 100 { print }' file.txt

    按字符串匹配

    • • 打印包含 "error" 的行:

      awk '/error/ { print }' file.txt

    不同方式的组合

    • • 打印第 2 列大于 50 且包含 "error" 的行:

      awk '$2 > 50 && /error/ { print }' file.txt

    BEGIN 和 END

    • • BEGIN 块在处理输入前执行,END 块在处理输入后执行:

      awk 'BEGIN { print "Start" } { print } END { print "End" }' file.txt

    2.7 计算

    统计数量:工时超过 15 小时的员工人数

    awk '$3 > 15 { count++ } END { print count }' file.txt

    求和、求平均:平均工资

    awk '{ sum += $2 } END { print "Average:", sum/NR }' file.txt

    处理文本:打印时薪最高的员工信息

    awk '$4 > max { max = $4; line = $0 } END { print line }' file.txt

    字符串拼接(concatenation):在一行内打印所有员工名

    awk '{ names = names $1 " " } END { print names }' file.txt

    打印最后一行

    awk '{ last = $0 } END { print last }' file.txt

    内置函数

    • • 统计行数、单词数、字符数:

      awk '{ chars += length($0); words += NF } END { print "Lines:", NR, "Words:", words, "Chars:", chars }' file.txt

    2.8 控制流

    If-Else

    awk '{ if ($1 > 50) print "High"; else print "Low" }' file.txt

    While

    awk '{ i = 1; while (i <= NF) { print $i; i++ } }' file.txt

    For

    awk '{ for (i = 1; i <= NF; i++) print $i }' file.txt

    2.9 数组

    统计每列的总和:

    awk '{ for (i = 1; i <= NF; i++) sum[i] += $i } END { for (i in sum) print "Column", i, "Sum:", sum[i] }' file.txt

    3. AWK 示例速查表

    以下是常见 AWK 功能及其对应程序和类似命令:

    编号功能AWK 程序类似命令
    1打印总行数END { print NR }wc -l
    2打印第 10 行NR == 10 { print }sed -n '10p'
    3打印最后一列{ print $NF }无
    4打印最后一行的最后一列{ f = $NF } END { print f }tail -n1
    5打印有 4 列以上的行NF > 4 { print }无
    6打印最后一列的值大于 4 的行$NF > 4 { print }无
    7打印所有输入的总字段数{ nf += NF } END { print nf }无
    8打印包含关键字的总行数/keyword/ { n++ } END { print n }grep -c 'keyword'
    9打印第 1 列的最大值及对应的行$1 > max { max = $1; line = $0 } END { print max, line }无
    10打印列数大于 1 的行NF > 1 { print }无
    11打印长度大于 80 的行length($0) > 80 { print }无
    12打印每行的列数和该行内容{ print NF, $0 }无
    13打印第 2 列和第 1 列{ print $2, $1 }无
    14交换第 1 列和第 2 列{ t = $1; $1 = $2; $2 = t; print }无
    15第 1 列替换为行号{ $1 = NR; print }无
    16删除第 2 列并打印{ $2 = ""; print }无
    17倒序打印每行的字段{ for (i=NF; i>0; i--) printf "%s ", $i; printf "\n" }无
    18计算每行的字段和{ sum=0; for (i=1; i<=NF; i++) sum += $i; print sum }无
    19计算所有字段的总和{ for (i=1; i<=NF; i++) sum += $i } END { print sum }无
    20将所有字段取绝对值并打印{ for (i=1; i<=NF; i++) if ($i<0) $i = -$i; print }无