AWK 是一种强大的文本处理工具,它允许用户以编程方式分析和转换文本数据。AWK 的名称来源于其三位创始人的姓氏首字母:Alfred Aho、Peter Weinberger 和 Brian Kernighan。AWK 适用于 Unix/Linux 环境下的 shell 编程,并且可以处理大型文本文件。
基本用法
AWK 的基本语法如下:
awk 'pattern { action }' input-file
pattern
:表示要搜索的模式,可以是正则表达式或条件表达式。action
:表示在匹配到模式时要执行的命令或操作。input-file
:表示要处理的输入文件。
内置变量
AWK 提供了一些内置变量,这些变量在程序运行时会自动赋值。以下是一些常用的内置变量:
FS
:字段分隔符(Field Separator),默认为空格或制表符。OFS
:输出字段分隔符(Output Field Separator),默认为空格。NR
:当前记录数(Number of Records)。NF
:当前记录中的字段数(Number of Fields)。$0
:当前记录(整行)。$1, $2, ...
:当前记录中的各个字段。
操作符
AWK 支持多种操作符,包括算术操作符、赋值操作符、比较操作符、逻辑操作符等。以下是一些常用的操作符:
+ - * / %
:算术操作符,分别表示加、减、乘、除、取模。= += -= *= /= %=
:赋值操作符,用于为变量赋值或修改其值。< <= > >= == !=
:比较操作符,用于比较两个值的大小或是否相等。&& || !
:逻辑操作符,分别表示与、或、非。
函数
AWK 提供了一些内置函数,用于执行常见的文本处理任务。以下是一些常用的函数:
length([string])
:返回字符串的长度。substr(string, start, [length])
:返回字符串的子串。index(string, substring)
:返回子串在字符串中首次出现的位置。split(string, array, [fieldsep])
:将字符串拆分为数组。tolower(string)
:将字符串转换为小写。toupper(string)
:将字符串转换为大写。
模式匹配
AWK 支持使用正则表达式进行模式匹配。正则表达式是一种用于描述文本模式的字符串,它可以包含普通字符和特殊字符(如元字符)。以下是一些常用的正则表达式元字符:
.
:匹配任意单个字符。*
:匹配零个或多个前面的字符。+
:匹配一个或多个前面的字符。?
:匹配零个或一个前面的字符。^
:匹配行的开头。$
:匹配行的结尾。[]
:匹配方括号内的任意单个字符。|
:表示“或”的关系。
示例
以下是一些使用 AWK 的示例,展示了其实际应用:
示例 1:打印文件中的每一行
awk '{ print }' input.txt
这个命令将打印 input.txt
文件中的每一行。{ print }
是 AWK 的默认动作,因此也可以省略。
示例 2:按字段分隔符打印字段
假设 input.csv
文件的内容如下:
name,age,city
Alice,30,New York
Bob,25,Los Angeles
Charlie,35,Chicago
我们可以使用 AWK 来打印文件中的特定字段:
awk -F, '{ print $1, $3 }' input.csv
这个命令将使用逗号作为字段分隔符,并打印每行的第一个和第三个字段(即姓名和城市)。
示例 3:按条件过滤记录
我们可以使用 AWK 来按条件过滤记录。例如,打印年龄大于 30 的记录:
awk -F, '$2 > 30 { print }' input.csv
这个命令将使用逗号作为字段分隔符,并打印年龄大于 30 的记录。
示例 4:计算字段的总和
我们可以使用 AWK 来计算字段的总和。例如,计算所有人的年龄总和:
awk -F, '{ sum += $2 } END { print sum }' input.csv
这个命令将使用逗号作为字段分隔符,并计算第二字段(年龄)的总和。END
是一个特殊的模式,表示在处理完所有记录后执行的动作。
示例 5:使用正则表达式匹配模式
我们可以使用正则表达式来匹配特定的模式。例如,打印包含字母 "a" 的记录:
awk '/a/ { print }' input.txt
这个命令将打印 input.txt
文件中包含字母 "a" 的每一行。
高级用法
AWK提供了许多高级特性,使得它能够处理更复杂的文本和数据。以下是一些AWK的高级用法,包括数组、用户自定义函数、命令行参数传递、多文件处理、排序和合并等,并附有具体的示例。
数组
AWK支持关联数组(也称为哈希表或字典),允许使用字符串作为索引。这在处理文本数据时非常有用。
示例:统计文件中每个单词出现的次数
awk '{for (i = 1; i <= NF; i++) {word_counts[$i]++}
} END {for (word in word_counts) {print word, word_counts[word]}
}' input.txt
用户自定义函数
AWK允许用户定义自己的函数,以执行特定的任务。这增加了代码的模块化和可读性。
示例:定义一个函数来计算两个数的和
awk '
function add(a, b) {return a + b
}
BEGIN {print add(3, 4) # 输出7
}'
命令行参数传递
AWK脚本可以接受命令行参数,这使得脚本更加灵活和可配置。
示例:从命令行传递一个文件名并打印其内容
awk 'BEGIN { filename = ARGV[1]; ARGV[1] = ""; } { print } END { exit }' input.txt
在这个示例中,ARGV[1]
被设置为输入文件名,然后从ARGV
数组中移除,以便awk
不将其视为要处理的输入文件。然后,{ print }
动作将打印文件的内容。注意,这种方法并不是传递参数的最佳实践,因为它依赖于修改ARGV
数组。更常见的是使用-v
选项来传递变量。
更好的做法:
awk -v filename=input.txt 'BEGIN { print "Reading file:", filename } { print }' $filename
多文件处理
AWK可以同时处理多个文件,并对它们执行相同的操作。这对于比较和分析来自不同源的数据非常有用。
示例:比较两个文件中相同行的数量
awk 'NR==FNR { lines[$0]++; next } $0 in lines { count++ } END { print count }' file1.txt file2.txt
在这个示例中,NR==FNR
条件在处理第一个文件时为真,此时将每行的内容存储在lines
数组中。在处理第二个文件时,如果某行存在于lines
数组中,则count
变量递增。最后,打印出相同行的数量。
排序和合并
虽然AWK本身不直接提供排序功能,但它可以与sort
命令结合使用来对数据进行排序。此外,AWK还可以用于合并已排序的文件,类似于merge
操作。
示例:合并两个已排序的文件(假设文件按数值字段的第一列排序)
awk '
BEGIN { OFS="\t" }
NR==FNR { a[$0]; next }
{if ($1 in a) {print $0, "from file2";delete a[$0]} else {b[NR] = $0}
}
END {for (i in a) print i, "from file1";for (i in b) print b[i];
}' file1.txt file2.txt
这个示例假设两个文件都按第一列进行排序。它使用两个数组a
和b
来分别存储来自file1.txt
和file2.txt
的行。在处理第二个文件时,如果某行的第一列值已存在于a
数组中,则打印该行并标记为来自file2
。否则,将该行存储在b
数组中。最后,打印剩余的行(即只存在于一个文件中的行)。
请注意,这个示例中的合并逻辑可能不适用于所有情况,特别是当文件包含重复行或需要按多个字段进行排序时。在实际应用中,可能需要更复杂的逻辑来处理这些情况。