字段与文本块(Fields and Blocks)

Awk 的字符串搜索不仅限于整行匹配,还可以限定搜索范围,例如只匹配特定的字段或一组连续的行。


1. 限定字段搜索

我们可以限定搜索范围,使其只在特定字段中进行匹配。例如:

$1 ~ /^France$/

匹配第一列($1) 等于 "France" 的行,而:

$1 !~ /^Norway$/

匹配第一列($1) 不等于 "Norway" 的行。


2. 匹配文本块

Awk 允许匹配一组连续的行,可以使用两个搜索模式,分别匹配起始行结束行

/^Ireland/,/^Summary/
  • 匹配从 "Ireland" 开头的行,一直到**"Summary" 开头的行**。
  • 如果找不到 "Summary",那么**"Ireland" 之后的所有行都会被匹配**。

示例

Ireland history
Ireland is famous for its culture
Dublin is the capital
Summary of Ireland’s population

匹配到的内容

Ireland history
Ireland is famous for its culture
Dublin is the capital
Summary of Ireland’s population

3. 不是所有搜索模式都是正则表达式

Awk 的搜索模式可以是其他表达式,不一定是正则表达式。

3.1 按行号匹配

NR == 10

匹配第 10 行
NR 变量表示当前处理的行号(从 1 开始计数)。

匹配第 10 到 20 行

NR == 10, NR == 20

4. 比较运算符

Awk 支持多种比较运算符:

运算符 作用
< 小于
<= 小于等于
== 等于
!= 不等于
>= 大于等于
> 大于
~ 匹配正则表达式
!~ 不匹配正则表达式

示例

NF == 0

匹配空行(字段数为 0)。

$1 == "France"

匹配第一列($1)"France" 的行。

$1 ~ /^France$/

效果相同,但这里使用正则表达式,必须加 ^$ 来匹配完整单词。


5. 逻辑运算符

可以使用 &&(AND)和 ||(OR) 组合多个搜索模式。

示例

((NR >= 30) && ($1 == "France")) || ($1 == "Norway")
  • 匹配第 30 行之后France
  • 或者匹配所有 Norway

如果 France 在前 30 行,则不会匹配,而 Norway 总是匹配。


6. 处理字段为数字还是字符串

Awk 是弱类型(Weakly-Typed) 语言,变量可存储数字或字符串,Awk 会自动决定如何处理它们。

$1 == 100
  • 匹配第一列等于 100 的行。
$1 < 100
  • 如果 $1 是数字,正常比较。
  • 如果 $1 是字符串,Awk 会把它作为字符串,导致比较变得不可预测。

示例

awk 'BEGIN {print ("100" < "50")}'  

输出

1  (因为字符串 "100" 按字母序比 "50" 小)

结论

  • 数字比较没问题
  • 字符串比较可能导致错误

如何确保 $1 是数字

可以使用 数值运算 强制转换:

(($1 + 0) == $1) && ($1 > 100)
  • 如果 $1 是数字$1 + 0 仍然是数字,比较正常。
  • 如果 $1 是文本,Awk 会把 $1 解释为 0,然后 (0 == $1) 为假,避免错误比较。

示例

awk 'BEGIN {x="Hello"; print ((x+0) == x)}'

输出:

0  (字符串 "Hello" 不是数字)

7. 练习

  1. 打印少于 5 个单词的行,但忽略以 * 开头的行

    awk 'NF < 5 && $1 !~ /^\*/'
    
  2. 打印所有以数字开头的行

    awk '$1 ~ /^[0-9]/'
    
  3. 检查编号错误的行

    • 假设 data.txt 是编号的文本:
      1. First line
      2. Second line
      4. Fourth line (Wrong)
      5. Fifth line
      
    • 代码:
      awk '{ if ($1+0 != NR) print "Incorrect line:", NR, "->", $0 }' data.txt
      
    • 输出
      Incorrect line: 3 -> 4. Fourth line (Wrong)
      

结论

  • 可以限制搜索范围到某个字段$1 ~ /France/)。
  • 可以匹配文本块/^Start/,/^End/)。
  • 可以基于行号匹配NR == 10)。
  • 可以使用比较运算符<, ==, ~)。
  • 可以使用逻辑运算符&&, ||)。
  • 数字和字符串的比较需要小心,可以使用 ($1 + 0) == $1 进行数值验证。

在下一章,你将学习更多关于 字符串和数值处理 的高级技巧!

Last modified: Thursday, 30 January 2025, 1:12 AM