13、AWK与正则表达式:数据处理与文本匹配的强大工具

AWK与正则表达式:数据处理与文本匹配的强大工具

1. AWK命令基础

AWK是一个强大的数据处理工具,可用于从文件中过滤和显示内容,尤其适用于处理大文件。我们可以先打印整个文件,以熟悉命令语法,之后再将控制信息添加到AWK文件中,简化命令行操作。

  • 打印整个文件 :使用以下命令可以打印 /etc/passwd 文件的所有行:
$ awk ' { print } ' /etc/passwd

这等价于使用 $0 变量和 print 语句:

$ awk ' { print $0 }' /etc/passwd
  • AWK内置变量 :AWK提供了一些内置变量用于提取数据,如下表所示:
    | 变量 | 含义 |
    | ---- | ---- |
    | $0 | 整行内容 |
    | $1 | 第一个字段 |
    | $2 | 第二个字段 |
    | $3 | 第三个字段 |
    | … | … |
2. 指定字段分隔符

在处理 /etc/passwd 文件时,需指定字段分隔符为冒号,因为AWK的默认分隔符是空格、制表符或换行符。指定输入分隔符有两种方式:
- 使用 -F 选项 :简单易用,适用于不需要额外头部信息的情况。

$ awk -F":" '{ print $1 }' /etc/passwd
  • BEGIN 块中设置 :当需要使用 BEGIN 块显示头部信息时很有用。
$ awk ' BEGIN { FS=":" } { print $1 } ' /etc/passwd
3. BEGIN END 代码块
  • BEGIN :用于初始化操作,代码只执行一次。
  • END :常用于显示汇总数据,代码也只执行一次,而主代码块会对每一行进行处理。例如,打印 passwd 文件的总行数:
$ awk ' BEGIN { FS=":" } { print $1 } END { print NR } ' /etc/passwd

其中, NR 是AWK的内部变量,用于记录已处理的行数。我们还可以添加额外文本注释汇总数据,并利用单引号将代码跨多行书写:

$ awk ' BEGIN { FS=":" }
> { print $1 }
> END { print "Total:",NR } ' /etc/passwd

若要显示每行的行号和最终总行数,可使用以下命令:

$ awk ' BEGIN { FS=":" }
> { print NR,$1 }
> END { print "Total:",NR } ' /etc/passwd
4. 单独使用 END

可以单独使用 END 块,模拟 wc -l 命令统计文件行数:

$ awk ' END { print NR }' /etc/passwd
5. 选择特定行
  • 打印前五行:
$ awk ' NR < 6 ' /etc/passwd
  • 打印第8行到第12行:
$ awk ' NR==8,NR==12 ' /etc/passwd
6. 使用正则表达式匹配文本

使用正则表达式可以匹配行中的文本,例如查找以 bash 结尾的行:

$ awk ' /bash$/ ' /etc/passwd

使用正则表达式模式时,需用两个斜杠将模式括起来,如 /bash$/

7. AWK变量

AWK提供了许多内置变量,可简化工作,如下表所示:
| 变量 | 含义 |
| ---- | ---- |
| FIELDWIDTHS | 指定字段宽度 |
| RS | 指定记录分隔符 |
| FS | 指定字段分隔符 |
| OFS | 指定输出分隔符,默认为空格 |
| ORS | 指定输出记录分隔符 |
| FILENAME | 保存正在处理的文件名 |
| NF | 保存当前行的字段数 |
| FNR | 保存当前文件的记录号 |
| IGNORECASE | 忽略字符大小写 |

以下是一个示例文件:

John Doe
15 back street
(123) 455-3584

Mokhtar Ebrahim
10 Museum street
(456) 352-3541  

若要打印姓名和电话号码,可设置 FS 为换行符 \n RS 为空字符串:

$ awk 'BEGIN{FS="\n"; RS=""} {print $1,$3}' myfile

还可以使用 OFS ORS 设置输出格式:

$ awk 'BEGIN{FS="\n"; RS=""; OFS="*"} {print $1,$3}' myfile
8. NR FNR 的区别

NR 记录已处理的总行数, FNR 记录当前文件的记录号。通过以下示例可以看出区别:

$ awk 'BEGIN{FS="\n"}{print $1,"FNR="FNR}' myfile myfile
$ awk 'BEGIN {FS="\n"} {print $1,"FNR="FNR,"NR="NR} END{print "Total lines: ",NR}' myfile myfile

在处理多个文件时, FNR 会为每个文件重新从1开始计数,而 NR 会持续累加。

9. 用户自定义变量

可以像在其他编程语言中一样,在AWK中定义自己的变量,但变量名不能以数字开头。例如:

$ awk '
BEGIN{
var="Welcome to AWk programming"
print var
}'

也可以定义数字变量并进行计算:

$ awk '
BEGIN{
var1=2
var2=3
var3=var1+var2
print var3
}'

还可以进行字符串拼接:

$ awk '
BEGIN{
str1="Welcome "
str2=" To shell scripting"
str3=str1 str2
print str3
}'
10. 条件语句
  • if 语句 :用于过滤文件中的值。例如,过滤出大于50的值:
$ awk '{if ($1 > 50) print $1}' myfile

还可以使用 else 子句:

$ awk '{
if ($1 > 50)
{
x = $1 * 2
print x
} else
{
x = $1 * 3
print x
}}' myfile

若不使用花括号 {} ,可以用分号将语句写在同一行:

$ awk '{if ($1 > 50) print $1 * 2;  else print $1 * 3}' myfile
  • while 循环 :用于遍历每行的字段。例如,计算每行字段的平均值:
$ awk '{
total = 0
i = 1
while (i < 4)
{
total += $i
i++
}
mean = total / 3
print "Mean value:",mean
}' myfile
  • for 循环 :同样可用于遍历值,实现与 while 循环相同的结果:
$ awk '{
total = 0
for (var = 1; var < 4; var++)
{
total += $var
}
mean = total / 3
print "Mean value:",mean
}' myfile
11. 输出格式化

使用 print 命令输出时,可能会出现列不对齐的问题。可以使用 printf 函数指定列宽,改善输出格式。例如:

$ awk ' BEGIN { FS=":" }
> { printf "%10s %4d %17s\n",$1,$3,$7 } ' /etc/passwd

还可以添加头部信息:

$ awk 'BEGIN {FS=":" ;printf "%10s %4s %17s\n","Name","UID","Shell" }
> { printf "%10s %4d %17s\n",$1,$3,$7 } ' /etc/passwd

通过自定义函数,可以在AWK中添加颜色输出:

$ awk 'function green(s) {
> printf "\033[1;32m" s "\033[0m\n"
> }
> BEGIN {FS=":"; 
green("   Name:  UID:    Shell:") }
> { printf "%10s %4d %17s\n",$1,$3,$7 } ' /etc/passwd
12. 根据UID进一步过滤用户

可以根据用户的UID过滤用户。例如,打印UID大于999的标准用户:

$ awk -F":" '$3 > 999 ' /etc/passwd

打印UID小于等于101的用户:

$ awk -F":" '$3 < 101 ' /etc/passwd
13. AWK控制文件

为了简化命令行并方便后续编辑,可以创建AWK控制文件。例如,将格式化 passwd 文件的代码封装在 passwd.awk 文件中:

function green(s) { 
    printf "\033[1;32m" s "\033[0m\n" 
} 
BEGIN { 
    FS=":" 
    green("   Name:   UID:       Shell:") 
} 
{ 
    printf "%10s %4d %17s\n",$1,$3,$7 
} 

执行命令如下:

$ awk -f passwd.awk /etc/passwd
14. 内置函数

AWK提供了许多内置函数,包括数学函数和字符串处理函数。例如:

$ awk 'BEGIN{x=sqrt(5); print x}' 
$ awk 'BEGIN{x = "welcome"; print toupper(x)}'
15. 正则表达式基础

正则表达式是一种强大的文本匹配工具,可用于在文件中进行高级搜索。正则表达式由正则表达式引擎解释,用于匹配特定文本。

  • 正则表达式引擎 :Linux中有两种主要的正则表达式引擎:
  • 基本正则表达式(BRE)引擎
  • 扩展正则表达式(ERE)引擎

大多数Linux二进制工具(如 sed AWK )都支持这两种引擎, grep 需要使用 -E 选项来支持ERE,等同于使用 egrep

以下是正则表达式相关操作的流程:

graph TD;
    A[开始] --> B[选择正则表达式引擎];
    B --> C{选择BRE还是ERE};
    C -- BRE --> D[定义BRE模式];
    C -- ERE --> E[定义ERE模式];
    D --> F[使用sed或AWK进行匹配];
    E --> F;
    F --> G[输出匹配结果];
    G --> H[结束];

接下来我们将详细介绍如何定义BRE和ERE模式,以及如何使用 grep 进行文本匹配。通过掌握正则表达式,我们可以充分发挥 sed AWK 的强大功能,更高效地处理文本数据。

16. 定义 BRE 模式

基本正则表达式(BRE)是正则表达式的基础形式,在很多 Linux 工具中都有广泛应用。以下是一些常见的 BRE 模式及其示例:

  • 字符匹配
  • . :匹配任意单个字符。例如, a.c 可以匹配 abc adc 等。
  • [] :匹配方括号内指定的任意一个字符。例如, [abc] 可以匹配 a b c
  • [^ ] :匹配不在方括号内的任意一个字符。例如, [^abc] 可以匹配除 a b c 之外的任意字符。

  • 重复匹配

  • * :匹配前面的字符零次或多次。例如, ab*c 可以匹配 ac abc abbbc 等。
  • \{n\} :匹配前面的字符恰好 n 次。例如, a\{3\} 只能匹配 aaa
  • \{n,\} :匹配前面的字符至少 n 次。例如, a\{2,\} 可以匹配 aa aaa 等。
  • \{n,m\} :匹配前面的字符至少 n 次,最多 m 次。例如, a\{1,3\} 可以匹配 a aa aaa

  • 位置匹配

  • ^ :匹配行的开头。例如, ^abc 只匹配以 abc 开头的行。
  • $ :匹配行的结尾。例如, abc$ 只匹配以 abc 结尾的行。

以下是一个使用 BRE 模式在 AWK 中匹配以 root 开头的行的示例:

$ awk '/^root/ { print }' /etc/passwd

17. 定义 ERE 模式

扩展正则表达式(ERE)在 BRE 的基础上进行了扩展,提供了更强大的匹配功能。以下是一些 ERE 特有的模式及其示例:

  • 重复匹配扩展
  • + :匹配前面的字符一次或多次。例如, ab+c 可以匹配 abc abbbc 等,但不能匹配 ac
  • ? :匹配前面的字符零次或一次。例如, ab?c 可以匹配 ac abc
  • () :用于分组。例如, (ab)+ 可以匹配 ab abab 等。

  • 或匹配

  • | :表示或关系。例如, a|b 可以匹配 a b

以下是一个使用 ERE 模式在 AWK 中匹配以 root bin 开头的行的示例:

$ awk -E '/^(root|bin)/ { print }' /etc/passwd

18. 使用 grep 进行文本匹配

grep 是一个常用的文本搜索工具,支持 BRE 和 ERE 模式。以下是一些常见的 grep 使用示例:

  • 使用 BRE 模式
$ grep '^root' /etc/passwd

该命令将搜索 /etc/passwd 文件中以 root 开头的行。

  • 使用 ERE 模式
$ grep -E '^(root|bin)' /etc/passwd

该命令将搜索 /etc/passwd 文件中以 root bin 开头的行。

19. 综合应用示例

以下是一个综合应用 AWK 和正则表达式的示例,用于从 /etc/passwd 文件中筛选出 UID 大于 1000 且默认 shell 为 /bin/bash 的用户:

$ awk -F":" '$3 > 1000 && /\/bin\/bash$/ { print $1 }' /etc/passwd

该命令的执行步骤如下:
1. 使用 -F":" 指定字段分隔符为冒号。
2. $3 > 1000 筛选出 UID 大于 1000 的行。
3. /\/bin\/bash$/ 使用正则表达式筛选出默认 shell 为 /bin/bash 的行。
4. { print $1 } 打印符合条件的用户名。

20. 总结

通过本文的介绍,我们了解了 AWK 命令的强大功能,包括文件内容的显示与过滤、变量的使用、条件语句和循环的应用、输出格式化等。同时,我们也学习了正则表达式的基础知识,包括 BRE 和 ERE 模式的定义以及如何使用 grep 进行文本匹配。

AWK 和正则表达式的结合可以让我们更高效地处理和分析文本数据。在实际应用中,我们可以根据具体需求灵活运用这些工具和技术,提高工作效率。

以下是本文主要内容的总结表格:
| 主题 | 主要内容 |
| ---- | ---- |
| AWK 命令基础 | 打印文件内容、使用内置变量提取数据 |
| 指定字段分隔符 | 使用 -F 选项和 BEGIN 块设置分隔符 |
| BEGIN END 代码块 | 用于初始化和汇总数据 |
| 选择特定行 | 使用行号和正则表达式选择行 |
| AWK 变量 | 内置变量和用户自定义变量 |
| 条件语句 | if while for 循环 |
| 输出格式化 | 使用 printf 函数和自定义函数 |
| 根据 UID 过滤用户 | 根据 UID 范围筛选用户 |
| AWK 控制文件 | 简化命令行和方便编辑 |
| 内置函数 | 数学函数和字符串处理函数 |
| 正则表达式 | BRE 和 ERE 模式、 grep 的使用 |

希望本文能帮助你更好地掌握 AWK 和正则表达式的使用,在实际工作中发挥它们的强大威力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值