第5.1节:awk内置变量
1 第5.1节:awk内置变量
1.1 控制型变量
以下是按字母顺序排列的变量列表,你可通过修改这些变量来控制 awk
执行某些操作的方式。
特定于 gawk
的变量会标记有井号(#
)。这些变量属于 gawk
的扩展特性。在其他 awk
实现中,或者当 gawk
处于兼容模式时,它们不会有特殊作用(每个变量的描述中会注明任何例外情况 )。
1.1.1 BINMODE
在非 POSIX 系统上,此变量指定对所有 I/O 使用二进制模式。数值为 1、2 或 3 时,分别表示输入文件、输出文件或所有文件应使用二进制 I/O 。数值小于 0 会被视为 0 ,数值大于 3 会被视为 3 。另外,字符串值 "r"
或 "w"
分别表示输入文件和输出文件应使用二进制 I/O 。字符串值 "rw"
或 "wr"
表示所有文件都应使用二进制 I/O 。任何其他字符串值会被当作 "rw"
处理,但会导致 gawk
生成一条警告消息。mawk
也支持此变量,但仅支持使用数值。
1.1.2 CONVFMT
一个用于控制数字转换为字符串的规则的字符串,其工作方式实际上是,作为第一个参数传递给 sprintf()
函数。它的默认值是 "%.6g"
。CONVFMT
是由 POSIX 标准引入的。
1.1.3 FIELDWIDTHS
由空格分隔的列宽度列表,告知gawk
如何按固定列边界拆分输入。从版本4.2开始,每个字段宽度前可选择性地加上由冒号分隔的值,用于指定字段开始前要跳过的字符数。为FIELDWIDTHS
赋值会覆盖FS
和FPAT
在字段拆分方面的作用 。
1.1.4 FPAT
一个正则表达式(以字符串形式),告知gawk
根据匹配该正则表达式的文本来创建字段。为FPAT
赋值会覆盖FS
和FIELDWIDTHS
在字段拆分方面的作用。
1.1.5 FS
输入字段分隔符。其值可以是单字符字符串,也可以是多字符正则表达式,用于匹配记录中字段间的分隔符。若值为空字符串(""
),则记录中的每个字符都会成为单独的字段(此行为是gawk
的扩展特性,POSIX awk
未规定FS
为空字符串时的行为。不过,其他一些awk
版本也会特殊处理""
)。
默认值是 " "
,即由单个空格组成的字符串。作为特殊例外,此值意味着任意空格、制表符和/或换行符序列都算作一个分隔符,且记录开头和结尾的空格、制表符及换行符会被忽略。
你可通过命令行的-F
选项设置FS
的值,例如:
awk -F, 'program' input-files
若gawk
正使用FIELDWIDTHS
或FPAT
进行字段拆分,为FS
赋值会让gawk
恢复为基于FS
的常规字段拆分方式。简单执行FS = FS
(可附带解释性注释 )就能轻松实现这一点。
1.1.6 IGNORECASE
若IGNORECASE
为非零值或非空值,那么所有字符串比较以及所有正则表达式匹配都会不区分大小写。这适用于正则表达式匹配操作符~
和!~
、gensub()
、gsub()
、index()
、match()
、patsplit()
、split()
以及sub()
函数,也适用于记录终止符RS
的匹配,还有基于FS
和FPAT
的字段拆分。不过,IGNORECASE
的值不会影响数组下标,也不会影响使用单字符字段分隔符时的字段拆分。
1.1.7 LINT
当此变量为真(非零或非空)时,gawk
的行为等同于启用--lint
命令行选项(。若值为"fatal"
,lint
警告会变为致命错误;若值为"invalid"
,仅会发出关于实际无效内容的警告(此功能尚未完全实现 )。任何为真的值都会打印非致命警告。为LINT
赋假值会关闭lint
警告。
此变量是gawk
的扩展特性,在其他awk
实现中无特殊作用。与其他特殊变量不同,即便gawk
处于兼容模式,修改LINT
也会影响lint
警告的产生,就像 --lint
和 --traditional
选项可独立控制 gawk
行为的不同方面一样,程序执行期间对 lint
警告的控制,与正在运行的 awk
实现风格无关 。
(说明:--lint
用于开启代码检查类警告,--traditional
让 gawk
兼容传统 awk
行为;“flavor of awk” 意译为 “awk
实现风格” ,体现不同 awk
变体的特性 )
1.1.8 OFMT
控制使用 print
语句打印时,数字转换为字符串的格式。其工作方式是作为第一个参数传递给 sprintf()
函数。它的默认值是 "%.6g"
。早期版本的 awk
用 OFMT
指定一般表达式中数字转字符串的格式;现在这项功能由 CONVFMT
实现 。
1.1.9 OFS
输出字段分隔符。print
语句输出时,会在字段之间插入该分隔符。它的默认值是 " "
,即由单个空格组成的字符串 。
1.1.10 ORS
输出记录分隔符。每个 print
语句执行结束时会输出它。默认值是 "\n"
,即换行符 。
1.1.11 PREC
任意精度浮点数运算时使用的工作精度,默认是 53 位 。
1.1.12 ROUNDMODE
用于任意精度算术运算的舍入模式,默认是 "N"
(对应 IEEE 754 标准中的 roundTiesToEven;
1.1.13 RS
输入记录分隔符。默认值是包含单个换行符的字符串,这意味着一个输入记录就是文本中的一行。它也可以是空字符串,此时记录由连续的空行分隔。若它是正则表达式,记录则由匹配该正则表达式的输入文本分隔。RS
支持正则表达式是 gawk
的扩展特性。在大多数其他 awk
实现中,或者当 gawk
处于兼容模式时,只会使用 RS
值的第一个字符 。
1.1.14 SUBSEP
下标分隔符。默认值是 "\034"
,用于分隔多维数组下标的各部分。因此,表达式 foo["A", "B"]
实际访问的是 foo["A\034B"]
。
1.1.15 TEXTDOMAIN
用于在 awk
层面实现程序的国际化。它为源代码中经过特殊标记的字符串常量设置默认文本域,也用于 dcgettext()
、dngettext()
和 bindtextdomain()
函数(。TEXTDOMAIN
的默认值是 "messages"
。
1.2 用于传递信息的内置变量
以下是按字母顺序排列的变量列表,awk
会在特定情况下自动设置这些变量,以便向你的程序传递信息。
特定于 gawk
的变量会用井号(#
)标记。这些变量是 gawk
的扩展特性。在其他 awk
实现中,或者当 gawk
处于兼容模式时,它们不会有特殊含义:
1.2.1 ARGC、ARGV
awk
程序可用的命令行参数存储在一个名为 ARGV
的数组中。ARGC
是命令行参数的数量。与大多数 awk
数组不同,ARGV
的索引从 0 到 ARGC - 1
。看以下示例:
$ awk 'BEGIN {for (i = 0; i < ARGC; i++)print ARGV[i]}' inventory-shipped mail-list
-| awk
-| inventory-shipped
-| mail-list
ARGV[0]
包含 awk
,ARGV[1]
包含 inventory-shipped
,ARGV[2]
包含 mail-list
。ARGC
的值是 3 ,比 ARGV
最后一个元素的索引大 1 ,因为元素是从 0 开始编号的。
ARGC
和 ARGV
的命名,以及数组索引从 0 到 ARGC - 1
的惯例,源自 C 语言访问命令行参数的方式。
ARGV[0]
的值在不同系统上可能不同。另外要注意,程序文本不会包含在 ARGV
中,awk
的任何命令行选项也不会。想了解 awk
如何使用这些变量 。
1.2.2 ARGIND
当前正在处理文件在 ARGV
中的索引。每当 gawk
打开一个新数据文件进行处理时,会将 ARGIND
设置为该文件名在 ARGV
中的索引。当 gawk
处理输入文件时,FILENAME == ARGV[ARGIND]
始终为真。
此变量在文件处理中很有用:它能让你知晓在数据文件列表中处理到了什么位置,还能区分命令行上连续出现的同名文件实例。
虽然你可在 awk
程序中修改 ARGIND
的值,但 gawk
打开下一个文件时,会自动将其设为新值。
1.2.3 ENVIRON
一个关联数组,包含环境变量的值;数组索引是环境变量的名称,元素是对应环境变量的值。例如,ENVIRON["HOME"]
的值可能是 /home/arnold
。
对于 POSIX awk
,修改此数组不会影响传递给 awk
衍生出的程序的环境(通过重定向或 system()
函数 )。不过,从版本 4.2 开始,若 gawk
处于非 POSIX 兼容模式,修改 ENVIRON
时,gawk
会更新自身环境,进而改变它创建的程序所看到的环境。因此,你若在 gawk
中修改 ENVIRON
,要留意对后续衍生程序环境的影响。因此,如果你修改 ENVIRON["PATH"]
时应格外小心,因为它是查找可执行程序的搜索路径。
这也可能会影响正在运行的 gawk
程序,因为某些内置函数可能会关注特定的环境变量。最显著的例子是 mktime()
,在许多系统上,它会关注 TZ
环境变量的值。
有些操作系统可能没有环境变量。在这类系统上,ENVIRON
数组是空的(ENVIRON["AWKPATH"]
和 ENVIRON["AWKLIBPATH"]
除外。
1.2.4 ERRNO
若在为 getline
进行重定向期间、getline
读取期间,或者 close()
操作期间发生系统错误,ERRNO
会包含一个描述该错误的字符串。
此外,gawk
在打开每个命令行输入文件前,会清空 ERRNO
。这使得可以在 BEGINFILE
模式中检查文件是否可读。
除此之外,ERRNO
的工作方式类似于 C 语言的 errno
变量。除了刚提到的情况,gawk
从不会清空它(设为 0 或空字符串 ""
)。因此,只有当 I/O 操作返回失败值(比如 getline
返回 -1 )时,你才应期望它的值有意义。当然,你完全可以在执行 I/O 操作前自行清空它。
若 ERRNO
的值对应 C 语言 errno
变量中的系统错误,PROCINFO["errno"]
会被设为 errno
的值。对于非系统错误,PROCINFO["errno"]
会是 0 。
1.2.5 FILENAME
当前输入文件的名称。当命令行上未列出数据文件时,awk
从标准输入读取,此时 FILENAME
被设为 "-"
。
每次读取新文件时,FILENAME
会改变。在 BEGIN
规则中,FILENAME
的值是空字符串 ""
,因为此时还未处理任何输入文件。不过要注意,在 BEGIN
规则中使用 getline
,可能会为 FILENAME
赋予一个值。
1.2.6 FNR
当前文件中的当前记录号。awk
每次读取一条新记录时,会递增 FNR
。
awk
每次开始处理一个新输入文件时,会将 FNR
重置为 0 。
1.2.7 NF
当前输入记录的字段数量。每当读取一条新记录、创建一个新字段,或者 $0
发生变化时,NF
会被设置。
与本小节描述的大多数变量不同,为 NF
赋值有可能影响 awk
的内部运作。具体而言,对 NF
赋值可用于在当前记录中创建字段或删除字段。
1.2.8 PROCINFO
该数组的元素可用于获取关于正在运行的 awk
程序的信息。以下元素(按字母顺序列出 )保证可用:
1.2.8.1 PROCINFO[“argv”]
PROCINFO["argv"]
数组包含所有命令行参数(在支持通配符扩展和重定向处理的平台上,这些处理是程序需手动完成的 ),下标范围从 0 到 argc - 1
。例如,PROCINFO["argv"][0]
会包含调用 gawk
时所用的名称。以下是一个说明该特性用法的示例:
gawk '
BEGIN {for (i = 0; i < length(PROCINFO["argv"]); i++)print i, PROCINFO["argv"][i]
}'
请注意,这与标准 ARGV
数组不同,标准 ARGV
数组不包含已被 gawk
处理过的命令行参数。
1.2.8.2 PROCINFO[“egid”]
getegid()
系统调用的返回值。
1.2.8.3 PROCINFO[“errno”]
当 ERRNO
被设为相关错误消息时,C 语言 errno
变量的值。
1.2.8.4 PROCINFO[“euid”]
geteuid()
系统调用的返回值。
1.2.8.5 PROCINFO[“FS”]
若当前是用 FS
进行字段拆分,值为 "FS"
;若用 FIELDWIDTHS
进行字段拆分,值为 "FIELDWIDTHS"
;若用 FPAT
进行字段匹配拆分,值为 "FPAT"
;若字段拆分由 API 输入解析器控制,值为 "API"
。
1.2.9 PROCINFO[“gid”]
getgid()
系统调用的返回值。
1.2.10 PROCINFO[“identifiers”]
一个子数组,下标为 awk
程序文本中使用的所有标识符名称。标识符指的是变量(无论是标量还是数组 )、内置函数、用户定义函数或扩展函数的名称。对于每个标识符,该元素的值为以下之一:
"array"
:标识符是数组。"builtin"
:标识符是内置函数。"extension"
:标识符是通过@load
或-l
加载的扩展函数。"scalar"
:标识符是标量。"untyped"
:标识符无类型(可作为标量或数组使用;gawk
尚未确定其类型 )。"user"
:标识符是用户定义函数。
这些值表示 gawk
解析完程序后对标识符的认知;程序运行期间不会更新。
1.2.10.1 PROCINFO[“platform”]
此元素提供一个字符串,表明 gawk
编译所针对的平台。其值为以下之一:
"mingw"
:Microsoft Windows,使用 MinGW 编译。"os390"
:OS/390(也称为 z/OS )。"posix"
:GNU/Linux、Cygwin、macOS 以及传统类 Unix 系统。"vms"
:OpenVMS。
1.2.10.2 PROCINFO[“pgrpid”]
当前进程的进程组 ID 。
1.2.10.3 PROCINFO[“pid”]
当前进程的进程 ID 。
1.2.10.4 PROCINFO[“pma”]
编译到 gawk
中的 PMA 内存分配器的版本。若 PMA 分配器不可用,此元素不存在。
1.2.10.5 PROCINFO[“ppid”]
当前进程的父进程 ID 。
1.2.10.6 PROCINFO[“strftime”]
strftime()
函数的默认时间格式字符串。为此元素赋值会改变默认格式。
1.2.10.7 PROCINFO[“uid”]
getuid()
系统调用的返回值。
1.2.10.8 PROCINFO[“version”]
gawk
的版本。
以下额外数组元素可在你的 gawk
版本支持任意精度算术运算时,提供关于 MPFR 和 GMP 库的信息:
1.2.10.9 PROCINFO[“gmp_version”]
GNU MP 库的版本。
1.2.10.10 PROCINFO[“mpfr_version”]
GNU MPFR 库的版本。
1.2.10.11 PROCINFO[“prec_max”]
MPFR 支持的最大精度。
1.2.10.12 PROCINFO[“prec_min”]
MPFR 要求的最小精度。
以下额外数组元素可在你的 gawk
版本支持动态加载扩展函数时,提供关于扩展 API 版本的信息:
1.2.10.13 PROCINFO[“api_major”]
扩展 API 的主版本号。
1.2.10.14 PROCINFO[“api_minor”]
扩展 API 的次版本号。
在部分系统中,数组里可能有 "group1"
到 "groupN"
(N
为某个数 )形式的元素。N
是进程所属补充组的数量。可使用 in
运算符测试这些元素是否存在。
以下元素可用于改变 gawk
的行为:
1.2.10.15 PROCINFO[“BUFFERPIPE”]
若此元素存在,所有输出到管道的内容会被缓冲。
1.2.10.16 PROCINFO[“command”, “BUFFERPIPE”]
使输出到指定命令的内容被缓冲。
1.2.10.17 PROCINFO[“NONFATAL”]
若此元素存在,所有重定向操作的 I/O 错误会变为非致命错误。
1.2.10.18 PROCINFO[“name”, “NONFATAL”]
使针对 name
的 I/O 错误变为非致命错误。
1.2.10.19 PROCINFO[“command”, “pty”]
若要与 command
进行双向通信,使用伪终端(pseudo-tty )而非建立双向管道。
1.2.10.20 PROCINFO[“input_name”, “READ_TIMEOUT”]
为从输入重定向 input_name
读取数据设置超时时间。
1.2.10.21 PROCINFO[“input_name”, “RETRY”]
从 input_name
读取数据时,若发生可重试的 I/O 错误,且此数组项存在,getline
会返回 -2 ,而非默认返回 -1 并将 input_name
配置为不再返回数据。当 errno
值为 EAGAIN
、EWOULDBLOCK
、EINTR
或 ETIMEDOUT
时,I/O 错误可重试。此特性与 PROCINFO["input_name", "READ_TIMEOUT"]
配合使用,或在文件描述符被配置为非阻塞模式的场景中可能有用。
1.2.10.22 PROCINFO[“sorted_in”]
若 PROCINFO
中存在此元素,其值会控制 for (indx in array)
循环处理数组下标的顺序。这是一项高级特性,完整说明将延后;
1.2.11 RLENGTH
由 match()
函数匹配到的子字符串长度。调用 match()
函数会设置 RLENGTH
,其值为匹配字符串的长度,若未找到匹配则为 -1 。
1.2.12 RSTART
match()
函数匹配到的子字符串的起始字符索引。调用 match()
函数会设置 RSTART
,其值为字符串中匹配子字符串的起始位置,若未找到匹配则为 0 。
1.2.13 RT
每次读取一条记录时,若文本匹配记录分隔符 RS
指定的内容,RT
会被设置为该匹配文本。
1.2.14 SYMTAB
一个数组,其下标为程序中所有已定义的全局变量和数组的名称。SYMTAB
让 gawk
的符号表对 awk
程序员可见。gawk
解析程序时构建该数组,程序开始运行前就已完整。
此数组可用于间接访问变量的值(读或写 ):
foo = 5SYMTAB["foo"] = 4
print foo # 输出 4
isarray()
函数可用于测试 SYMTAB
中的元素是否为数组。另外,不能对 SYMTAB
数组使用 delete
语句。
在 gawk
5.0 版本之前,你可以对 SYMTAB
使用未预定义的下标,例如:
SYMTAB["xxx"] = 5
print SYMTAB["xxx"]
但这种用法现已失效,会产生致命错误,因为它曾导致严重混乱。
SYMTAB
数组比表面看起来更有意思。Andrew Schorr 指出,它实际上为 awk
提供了“数据指针”功能。看他的示例:
# 通过间接方式将任意变量乘以指定数值并返回结果
function multiply(variable, amount)
{return SYMTAB[variable] *= amount
}# 使用示例
BEGIN {answer = 10.5multiply("answer", 4)print "The answer is", answer
}
运行结果:
$ gawk -f answer.awk
The answer is 42
注意:为避免严重的“时间旅行悖论”,FUNCTAB
和 SYMTAB
都不能作为 SYMTAB
数组的元素。
1.2.15 关于 NR 和 FNR 的修改
awk
每次读取一条新记录时,会递增 NR
和 FNR
,而非将它们设为已读记录数量的绝对值。这意味着程序可修改这些变量,且后续每条记录读取时,新值会继续递增。以下示例展示了这一点:
$ echo '1'
> 2
> 3
> 4' | awk 'NR == 2 { NR = 17 }
> { print NR }'
-| 1
-| 17
-| 18
-| 19
在 FNR
被加入 awk
语言之前,许多 awk
程序利用此特性,在 FILENAME
改变时将 NR
重置为 0 ,以此跟踪文件中的记录数量。
1.2.16 使用 ARGC 和 ARGV
以下代码打印出包含在 ARGC
和 ARGV
中的信息:
$ awk 'BEGIN {for (i = 0; i < ARGC; i++)print ARGV[i]}' inventory-shipped mail-list
-| awk
-| inventory-shipped
-| mail-list
在此示例中,ARGV[0]
包含 awk
,ARGV[1]
包含 inventory-shipped
,ARGV[2]
包含 mail-list
。注意,awk
程序本身不会加入 ARGV
。其他命令行选项及其参数也不会加入,包括用 -v
选项进行的变量赋值。命令行上的常规变量赋值会被当作参数,显示在 ARGV
数组中。假设有一个名为 showargs.awk
的文件,内容如下:
BEGIN {printf "A=%d, B=%d\n", A, Bfor (i = 0; i < ARGC; i++)printf "\tARGV[%d] = %s\n", i, ARGV[i]
}
END { printf "A=%d, B=%d\n", A, B }
运行它会产生如下结果:
$ awk -v A=1 -f showargs.awk B=2 /dev/null
-| A=1, B=0-| ARGV[0] = awk
-| ARGV[1] = B=2
-| ARGV[2] = /dev/null
-| A=1, B=2
程序可修改 ARGC
和 ARGV
的元素。每当 awk
处理完一个输入文件,会使用 ARGV
的下一个元素作为下一个输入文件的名称。通过在 ARGV
中存储不同字符串,程序可改变要读取的文件。用 "-"
表示标准输入。存储额外元素并递增 ARGC
会使更多文件被读取。
若减小 ARGC
的值,会从列表末尾移除输入文件。程序可将 ARGC
的旧值记录到其他地方,把被移除的参数当作非文件名的内容处理。
要从列表中间移除文件,可在 ARGV
中对应文件名称的位置存入空字符串(""
)。作为特殊特性,awk
会忽略被替换为空字符串的文件名。另一种方式是使用 delete
语句从 ARGV
中移除元素
所有这些操作通常在 BEGIN
规则中完成,即在实际处理输入开始前。了解从 ARGV
移除元素的不同方式示例。
要真正把选项传入 awk
程序,需用 --
结束 awk
选项,然后在后续提供 awk
程序的选项,如下:
awk -f myprog.awk -- -v -q file1 file2 ...
以下代码片段会处理 ARGV
,检查并移除前面提到的命令行选项:
BEGIN {for (i = 1; i < ARGC; i++) {if (ARGV[i] == "-v")verbose = 1else if (ARGV[i] == "-q")debug = 1else if (ARGV[i] ~ /^-./) {e = sprintf("%s: unrecognized option -- %c",ARGV[0], substr(ARGV[i], 2, 1))print e > "/dev/stderr"} elsebreakdelete ARGV[i]}
}
在 gawk
中,用 --
结束 awk
选项并非必需。除非指定了 --posix
,否则 gawk
会悄悄将任何无法识别的选项放入 ARGV
,供 awk
程序处理。一旦遇到未知选项,gawk
会停止查找其他可能识别的选项。前面带 gawk
的命令行示例如下:
gawk -f myprog.awk -q -v file1 file2 ...
因为 -q
不是有效的 gawk
选项,它和后面的 -v
会被传递给 awk
程序
设计程序时,应选择不会与 gawk
冲突的选项,因为 gawk
会先处理它能识别的选项,再将剩余命令行内容传递给你的程序。结合 -E
选项使用 #!
可能会有帮助
作者声明:本文用于记录和分享作者的学习心得,可能有部分文字或示例来自AI平台,如:豆包、DeepSeek(硅基流动)(注册链接)等,由于本人水平有限,难免存在表达错误,欢迎留言交流和指教!
Copyright © 2022~2025 All rights reserved.