gawk5.1.1
源码的 awk.h
文件定义了 redirect
这个「重定向」结构体,里面有个 redirect_flags
标记枚举,有这几个值:
1 | RED_NONE = 0, |
后面主要关注 RED_FILE
、RED_WRITE
、RED_USED
这 3 个 flag。
awk 可开启 Lint 执行,会输出一些类似 DEBUG 的警告提示或错误提示:l--lint=invalid
。当进程所用到的 fd
超过 ulimit
的时候,标准错误会输出:
1 | warning: reached system limit for open files: starting to multiplex file descriptors |
源文件 io.c:1208-1210:
1 | if (do_lint && ! warned) { |
这个与 awk info 里面所述一致,然后 Lint 会报
1 | warning: unnecessary mixing of `>' and `>>' for file |
这个警告提示,说明 awk 内部已经把 >
换成了 >>
在执行,在执行层面上来看符合猜想,具体代码参考 io.c:819-826
:
1 | case redirect_output: |
至于 awk 如何判断这个文件是新打开的还是已有的文件,参考 gawkapi.c:1334-1423
的 api_get_file
函数。
最重要的就是解释如何「复用」数量有限的文件描述符(fd
),主要逻辑集中在 io.c
的 redirect_string
以及 close_one
函数。close_one
函数较为容易理解(io.c:1200-1235
),根据注释:临时关闭并打开文件进而复用文件描述符,具体逻辑为定位到「fd
使用热度链表」中最不常用的那个 fd
开始,依次往常用的 fd
遍历,如果能关闭则关闭之(当然像标准输入、标准输出及标准错误这三个 fd
是不能关闭的)。回到调用 close_one
函数的 redirect_string
函数(io.c:1070-1073
)后 931 行的 while 循环继续执行:
1 | while (rp->output.fp == NULL && rp->iop == NULL) { |
由于使用 print >
进行重定向,所以上述 switch(redirtype)
会走 redirect_output
分支,并重新使文件描述符与文件绑定(io.c:1026-1029):
1 | if (mode != NULL) { |
以上解释了 awk 如何在有限的系统 ulimit -n
设定下 print >
的表现如同 >>
且能正常处理文本。
附录
awk --lint=invalid
标准错误信息(节选):
1 | awk: cmd. line:1: (FILENAME=seq.txt FNR=97) warning: reached system limit for open files: starting to multiplex file descriptors |