> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/man/man1/awk.1.md).

# awk.1

`awk` — 基于模式的扫描和处理语言

## 名称

`awk`

## 概要

`awk [-safe] [-version] [-d[n]] [-F fs | --csv] [-v var=value] [prog | -f progfile] file`

## 描述

`awk` 扫描每个输入 `file`，查找与 `prog` 中字面指定的模式集合，或以 `-f` `progfile` 指定的一个或多个文件中的模式集合匹配的行。每个模式可关联一个动作，当 `file` 的某行匹配该模式时执行相应动作。每行与每个模式-动作语句的模式部分进行匹配；对每个匹配的模式执行关联的动作。文件名 ‘-’ 表示标准输入。任何 `var`=`value` 形式的 `file` 被视为赋值而非文件名，并在如果是文件名时本应被打开的时刻执行。

选项如下：

**`-d`** \[`n`] 调试模式。将调试级别设置为 `n`，未指定 `n` 时设为 1。大于 1 的值会导致 `awk` 在致命错误时转储核心。

**`-F`** `fs` 将输入字段分隔符定义为正则表达式 `fs`。

**`--csv`** 使 `awk` 使用（基本符合）标准逗号分隔值（CSV）格式处理记录。

**`-f`** `progfile` 从指定文件 `progfile` 而非命令行读取程序代码。

**`-safe`** 禁用文件输出（`print` >、`print` >>）、进程创建（`cmd |` `getline`、`print |`、`system`）以及对环境的访问（`ENVIRON`；参见下文变量部分）。这是“安全”版 `awk` 的初步（且不太可靠）近似实现。

**`-version`** 将 `awk` 的版本号打印到标准输出并退出。

**`-v`** `var`=`value` 在执行 `prog` 之前将 `value` 赋给变量 `var`；可以出现任意数量的 `-v` 选项。

输入通常由换行符或 `RS` 的值分隔的输入行（记录）组成。如果 `RS` 为空，则任意数量的空行用作记录分隔符，换行符用作字段分隔符（在 `FS` 的值之外）。这在处理多行记录时很方便。

输入行通常由空白或下文所述的扩展正则表达式 `FS` 分隔的字段组成。字段表示为 `$1 , $2 , ...`，而 `$0` 引用整行。如果 `FS` 为空，输入行按每个字符一个字段拆分。虽然 gawk 和 mawk 行为相同，但在 IEEE Std 1003.1-2008 ("POSIX.1") 标准中未明确规定。如果 `FS` 是单个空格，则跳过开头和结尾的空白和换行字符。字段由一个或多个空白或换行字符分隔。空白字符是空格或制表符。如果 `FS` 是除空格外的单个字符，字段由该字符的每次出现分隔。`FS` 变量默认为单个空格。

通常，任意数量的空白分隔字段。要将字段分隔符设置为单个空白，使用 `-F` 选项并指定值 ‘\[\ ]’。如果指定 ‘t’ 为字段分隔符，`awk` 将其视为指定了 ‘et’ 并使用 作为字段分隔符。要将字面 ‘t’ 用作字段分隔符，使用 `-F` 选项并指定值为 ‘\[t]’。

模式-动作语句形式为：

> `pattern` `{` `action` `}`

缺失 `{` `action` `}` 表示打印该行；缺失的模式总是匹配。模式-动作语句由换行符或分号分隔。

在终止语句后、逗号（‘,’）、左花括号（‘{’）、逻辑与（‘&&’）、逻辑或（‘||’）之后，‘do’ 或 ‘else’ 关键字之后，或 ‘if’、‘for’ 或 ‘while’ 语句的右括号之后，允许换行。此外，反斜杠（‘e’）可用于转义标记之间的换行。

动作是语句序列。语句可以是以下之一：

**`if`** `( expression`) `statement` \[`else` `statement`]

**`while`** `( expression`) `statement`

**`for`** `( expression ; expression ; expression ) statement`

**`for`** `( var` `in` `array ) statement`

**`do`** `statement` `while` `( expression`)

**`break`**

**`continue`**

`{` \[`statement ...`] `}`

`expression` # 常用形式 `var` = `expression`

`print` \[`expression-list`] \[>`expression`]

`printf` `format` \[`... , expression-list`] \[>`expression`]

**`return`** \[`expression`]

`next` # 跳过此输入行上的剩余模式

`nextfile` # 跳过此文件剩余部分，打开下一个文件，从顶部开始

`delete` `array` `[` `expression` `]` # 删除数组元素

`delete` `array` # 删除数组的所有元素

`exit` \[`expression`] # 立即退出；状态为 `expression`

语句以分号、换行或右花括号终止。空的 `expression-list` 代表 `$0`。字符串常量用 `""` 引起，其中识别常用的 C 转义序列（完整列表参见 printf(1)）。表达式根据情况取字符串或数值，并使用运算符 `+ - * / % ^`（指数）和连接（由空白指示）构建。运算符 `! ++ -- += -= *= /= %= ^=` `> >= < <= == != ?:` 也可用于表达式中。变量可以是标量、数组元素（表示为 `x[i]`）或字段。变量初始化为空字符串。数组下标可以是任何字符串，不一定是数字；这允许一种形式的关联存储。允许多个下标，如 `[i,j,k]`；各组成部分由 `SUBSEP` 的值分隔连接（参见下文变量部分）。

`print` 语句将其参数打印到标准输出（如果存在 >`file` 或 >>`file` 则打印到文件，如果存在 |\`cmd `则打印到管道），由当前输出字段分隔符分隔，由输出记录分隔符终止。`file`和`cmd `可以是字面名称或带括号的表达式；不同语句中相同的字符串值表示同一个打开的文件。`printf\` 语句根据格式格式化其表达式列表（参见 printf(1)）。

模式是正则表达式和关系表达式的任意布尔组合（使用 `! || &&`）。`awk` 支持扩展正则表达式（ERE）。有关正则表达式的更多信息，参见 re\_format(7)。模式中孤立的正则表达式应用于整行。正则表达式也可出现在关系表达式中，使用运算符 `~` 和 `!~`。/`re`/ 是常量正则表达式；任何字符串（常量或变量）都可用作正则表达式，但不能用作模式中孤立正则表达式的位置。

模式可由两个用逗号分隔的模式组成；在这种情况下，对从第一个模式出现到第二个模式出现（含）之间的所有行执行动作。

关系表达式是以下之一：

**`expression matchop regular-expression`**

**`expression relop expression`**

**`expression`** `in` `array-name`

`(` `expr , expr , ...``) in` `array-name`

其中 `relop` 是 C 中的六个关系运算符之一，`matchop` 是 `~`（匹配）或 `!~`（不匹配）。条件是算术表达式、关系表达式或它们的布尔组合。

特殊模式 `BEGIN` 和 `END` 可用于在读取第一行输入之前和最后一行之后捕获控制。`BEGIN` 和 `END` 不与其他模式组合。它们可在程序中多次出现，并按 `awk` 读取的顺序执行。

具有特殊含义的变量名：

**`ARGC`** 参数计数，可赋值。

**`ARGV`** 参数数组，可赋值；非空成员被取作文件名。

**`CONVFMT`** 转换数字时的转换格式（默认 "" `%.6g )`）。

**`ENVIRON`** 环境变量数组；下标是名称。

**`FILENAME`** 当前输入文件的名称。

**`FNR`** 当前文件中当前记录的序号。

**`FS`** 用于分隔字段的正则表达式；也可通过选项 `-F` `fs` 设置。

**`NF`** 当前记录中的字段数。`$NF` 可用于获取当前记录中最后一个字段的值。

**`NR`** 当前记录的序号。

**`OFMT`** 数字的输出格式（默认 "" `%.6g )`）。

**`OFS`** 输出字段分隔符（默认为空白）。

**`ORS`** 输出记录分隔符（默认为换行符）。

**`RLENGTH`** 由 `match()` 函数匹配的字符串长度。

**`RS`** 输入记录分隔符（默认为换行符）。如果为空，空行分隔记录。如果超过一个字符，`RS` 被视为正则表达式，记录由匹配该表达式的文本分隔。

**`RSTART`** 由 `match()` 函数匹配的字符串的起始位置。

**`SUBSEP`** 分隔多个下标（默认 034）。

## 函数

awk 语言有多种内置函数：算术、字符串、输入/输出、通用和位运算。

函数可定义（在模式-动作语句的位置）如下：

```sh
function foo(a, b, c) { ...; return x }
```

参数如果是标量则按值传递，如果是数组名则按引用传递；函数可递归调用。参数对函数是局部的；所有其他变量是全局的。因此可通过在函数定义中提供多余参数来创建局部变量。

### 算术函数

**`atan2(y, x)`** 返回 `y`/`x` 的反正切值（弧度）。

**`cos(x)`** 返回 `x` 的余弦值，`x` 以弧度为单位。

**`exp(x)`** 返回 `x` 的指数。

**`int(x)`** 返回 `x` 截断为整数值后的结果。

**`log(x)`** 返回 `x` 的自然对数。

**`rand()`** 返回随机数 `n`，满足 0 ≤ `n` < 1。

**`sin(x)`** 返回 `x` 的正弦值，`x` 以弧度为单位。

**`sqrt(x)`** 返回 `x` 的平方根。

**`srand(expr)`** 将 `rand()` 的种子设置为 `expr` 并返回之前的种子。如果省略 `expr`，则使用当前时间。

### 字符串函数

**`gsub(r, t, s)`** 与 `sub()` 相同，但替换所有出现的正则表达式。`gsub()` 返回替换次数。

**`index(s, t)`** 字符串 `t` 在 `s` 中出现的位置，如果未出现则为 0。

**`length(s)`** `s` 作为字符串的长度，对于数组参数是数组元素数，如果未给定参数则是 `$0` 的长度。

**`match(s, r)`** 正则表达式 `r` 在 `s` 中出现的位置，如果未出现则为 0。变量 `RSTART` 设置为匹配字符串的起始位置（与返回值相同），如果未找到匹配则为零。变量 `RLENGTH` 设置为匹配字符串的长度，如果未找到匹配则为 -1。

**`split(s, a, fs)`** 将字符串 `s` 拆分为数组元素 `a[1] , a[2] , ... , a[n]` 并返回 `n`。拆分使用正则表达式 `fs`，如果未给定 `fs` 则使用字段分隔符 `FS`。空字符串作为字段分隔符时将字符串按每个字符一个数组元素拆分。

**`sprintf(fmt, expr, ...)`** 根据 printf(1) 格式 `fmt` 格式化 `expr , ...` 所得的字符串。

**`sub(r, t, s)`** 用 `t` 替换字符串 `s` 中第一次出现的正则表达式 `r`。如果未给定 `s`，则使用 `$0`。`t` 中的 ‘&’ 在字符串 `s` 中被替换为正则表达式 `r`。字面 & 可通过在前面加两个反斜杠（‘ee’）指定。字面反斜杠可通过在前面加另一个反斜杠（‘ee’）指定。`sub()` 返回替换次数。

**`substr(s, m, n)`** 返回 `s` 中从位置 `m`（从 1 开始计数）开始、最多 `n` 个字符的子串。如果省略 `n`，或 `n` 指定的字符数超过字符串剩余字符数，子串长度受 `s` 长度限制。

**`tolower(str)`** 返回 `str` 的副本，将所有大写字符转换为对应的小写等效字符。

**`toupper(str)`** 返回 `str` 的副本，将所有小写字符转换为对应的大写等效字符。

### 输入/输出和通用函数

**`close(expr)`** 关闭文件或管道 `expr`。`expr` 应与用于打开文件或管道的字符串匹配。

**`cmd |`** `getline` \[`var`] 从 `cmd` 输出管道流中读取一条输入记录。如果省略 `var`，则设置变量 `$0` 和 `NF`。否则设置 `var`。如果流未打开，则打开它。只要流保持打开，后续调用将从流中读取后续记录。流保持打开，直到通过调用 `close()` 显式关闭。`getline` 成功输入返回 1，文件末尾返回 0，错误返回 -1。

**`fflush([expr])`** 刷新文件或管道 `expr` 的所有缓冲输出，如果省略 `expr` 则刷新所有打开的文件或管道。`expr` 应与用于打开文件或管道的字符串匹配。

**`getline`** 将 `$0` 设置为当前输入文件的下一条输入记录。此形式的 `getline` 设置变量 `NF`、`NR` 和 `FNR`。`getline` 成功输入返回 1，文件末尾返回 0，错误返回 -1。

**`getline`** `var` 将 `$0` 设置为变量 `var`。此形式的 `getline` 设置变量 `NR` 和 `FNR`。`getline` 成功输入返回 1，文件末尾返回 0，错误返回 -1。

**`getline`** \[`var`] <`file` 将 `$0` 设置为 `file` 的下一条记录。如果省略 `var`，则设置变量 `$0` 和 `NF`。否则设置 `var`。如果 `file` 未打开，则打开它。只要流保持打开，后续调用将从 `file` 读取后续记录。`file` 保持打开，直到通过调用 `close()` 显式关闭。

**`systime()`** 返回当前日期和时间作为标准的“自纪元以来的秒数”值。

**`strftime(fmt, timestamp)`** 根据 `fmt`（一个 strftime(3) 支持的格式字符串）格式化 `timestamp`（一个自纪元以来的秒数值）。`timestamp` 和 `fmt` 都可省略；如果没有 `timestamp`，使用当前时间；如果没有 `fmt`，使用默认格式 "%a %b %e %H:%M:%S %Z %Y"。

**`system(cmd)`** 执行 `cmd` 并返回其退出状态。错误时为 -1，正常退出时为 `cmd` 的退出状态，被信号杀死时为 256 + `sig`（其中 `sig` 是致命信号的编号），如果发生核心转储则为 512 + `sig`。

### 位运算函数

**`compl(x)`** 返回整数参数 x 的按位补码。

**`and(v1, v2, ...)`** 对所有提供的参数（作为整数）执行按位与。至少需要两个值。

**`or(v1, v2, ...)`** 对所有提供的参数（作为整数）执行按位或。至少需要两个值。

**`xor(v1, v2, ...)`** 对所有提供的参数（作为整数）执行按位异或。至少需要两个值。

**`lshift(x, n)`** 返回整数参数 x 左移 n 位的结果。

**`rshift(x, n)`** 返回整数参数 x 右移 n 位的结果。

## 退出状态

`awk` 实用程序在成功时退出 0，发生错误时退出 >0。

但请注意，`exit` 表达式可修改退出状态。

## 环境变量

如果环境中设置了 `POSIXLY_CORRECT`，则 `awk` 在处理连续反斜杠和 & 字符方面遵循 `sub()` 和 `gsub()` 的 POSIX 规则。

## 实例

打印长度超过 72 个字符的行：

```sh
length($0) > 72
```

以相反顺序打印前两个字段：

```sh
{ print $2, $1 }
```

同上，但输入字段由逗号和/或空格与制表符分隔：

```sh
BEGIN { FS = ",[ et]*|[ et]+" }
      { print $2, $1 }
```

累加第一列，打印总和和平均值：

```sh
{ s += $1 }
END { print "sum is", s, " average is", s/NR }
```

打印 start/stop 对之间的所有行：

```sh
/start/, /stop/
```

模拟 echo(1)：

```sh
BEGIN { # 模拟 echo(1)
        for (i = 1; i < ARGC; i++) printf "%s ", ARGV[i]
        printf "en"
        exit }
```

向标准错误打印错误信息：

```sh
{ print "error!" > "/dev/stderr" }
```

## 参见

[cut(1)](/man/man1/cut.1.md), lex(1), printf(1), [sed(1)](/man/man1/sed.1.md), re\_format(7)

> A. V. Aho, B. W. Kernighan, P. J. Weinberger, "The AWK Programming Language", Addison-Wesley, 1988, ISBN 0-201-07981-X.

## 标准

`awk` 实用程序符合 IEEE Std 1003.1-2008 ("POSIX.1") 规范，但 `awk` 不支持 {n,m} 模式匹配。

标志 `-d`、`-safe` 和 `-version` 以及命令 `fflush , compl , and , or`、`xor , lshift , rshift` 是该规范的扩展。

## 历史

`awk` 实用程序首次出现在 Version 7 AT\&T UNIX。

## 缺陷

数字和字符串之间没有显式转换。要强制将表达式视为数字，对其加 0；要强制将其视为字符串，连接 `""`。

函数中变量的作用域规则是拙劣的；语法更糟。

输入预期为 UTF-8 编码。不处理其他多字节字符集。但是，在八位区域设置中，`awk` 将每个输入字节视为单独的字符。

## 不寻常的浮点值

`awk` 设计于 IEEE 754 算术定义非数字（NaN）和无穷大值之前，而所有现代浮点硬件都支持这些值。

由于 `awk` 使用 strtod(3) 和 atof(3) 将字符串值转换为双精度浮点值，现代 C 库也会将以 `inf` 和 `nan` 开头的字符串分别转换为无穷大和 NaN 值。这导致了奇怪的结果，例如：

```sh
echo nancy | awk '{ print $1 + 0 }'
```

打印 "nan" 而不是零。

`awk` 现在遵循 GNU AWK，在尝试将字符串值转换为数字之前对其进行预过滤，规则如下：

**十六进制**值 自 C99 起允许的十六进制值转换为零，与 C99 之前的行为相同。

**NaN**值 两个字符串 "+nan" 和 "-nan"（不区分大小写）转换为 NaN。其他字符串不会转换。（NaN 可以有符号。）

**无穷大**值 两个字符串 "+inf" 和 "-inf"（不区分大小写）分别转换为正无穷和负无穷。其他字符串不会转换。

## 已弃用的行为

One True Awk 接受 `-F` `t` 作为 `-F` `<TAB>` 的同义词，以便更方便地将制表符指定为分隔符。为了与 gawk 和 mawk 等其他 awk 实现更好的兼容性，上游 One True Awk 已弃用此瑕疵。

历史上，`awk` 不接受 "0x" 作为十六进制字符串。但是，由于 One True Awk 使用 strtod 将字符串转换为浮点数，并且 "0x12" 是浮点数的有效十六进制表示，在 FreeBSD 上，自 One True Awk 在 FreeBSD 5.0 中导入以来，`awk` 已接受此表示法作为扩展。为了在不同 awk 实现之间获得更好的兼容性，上游 One True Awk 已恢复历史行为。gawk 和 mawk 已经表现得类似。从 FreeBSD 14.0 开始，`awk` 将不再接受此扩展。

FreeBSD `awk` 多年来将区域设置设置为与其运行环境匹配。这导致模式范围（如 "\[A-Z]"）在某些区域设置中有时匹配小写字符。这种不当行为从未出现在上游 One True Awk 中，并已在 FreeBSD 12.3、FreeBSD 13.1 和 FreeBSD 14.0 中作为错误删除。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/man/man1/awk.1.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
