为什么 awk -F 对大多数字母有效,但对字母“t”无效?

为什么 awk -F 对大多数字母有效,但对字母“t”无效?
 July 2022      mac os Monterey V12.1 
   awk --version 20200816
   GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin21)

为什么awk -F适用于大多数字母,但不适用于字母t?我有解决方案,但我想了解为什么 awk 对于 letter 失败t

# Count 'e's
% echo "tweeter" | awk -F "e" '{print NF-1}'
3

# Count 'r's
% echo "tweeter" | awk -F "r" '{print NF-1}'
1

# (Attempt to) count 't's
% echo "tweeter" | awk -F "t" '{print NF-1}'
0   <=== ????

# Use gsub()
% echo "tweeter" | awk '{print gsub(/t/, "")}'
2

答案1

因为:

通常,任意数量的空格分隔字段。要将字段分隔符设置为单个空格,请使用值为 的 -F 选项 [ ]如果指定了字段分隔符t,awk 会将其视为 \t已指定并使用 <TAB> 作为字段分隔符。 为了使用文字t作为字段分隔符,请使用值为 的 -F 选项[t]

那是来自FreeBSD awk 手册页,macOS 附带的实用程序通常是一些旧的 FreeBSD 版本等。

$ printf 'foo\tbar\n' | awk -F t '{print NF-1}'
1
$ echo total | awk -F '[t]' '{print NF-1}'
2

在某种程度上,这对于具有制表符分隔值的文件来说似乎是一个有用的速记,但是对于按原样采用的其他字母,它会令人困惑。它只能像 with 那样工作-F,而 using 则-v FS=t不起作用。

该功能是非 POSIX 的,因为POSIX 说-F x与 相同-v FS=x。我测试的大多数其他 awks 都被t视为字面字母(某些版本的 gawk、mawk 和 Busybox)。

例如 Debian 中的 awk 版本original-awk包裹(“One True AWK”或“BWK awk”大概来自 Brian W. Kernighan 的姓名缩写)确实支持它,并且至少维基百科似乎表明这与 FreeBSD 使用的软件相同。这个版本似乎是基于 1988 年的《The AWK 编程语言》一书中描述的版本,但我不是 awk 谱系的专家,也不知道从那时起它是否已经发生了显着的演变。那个在 github 上,但那里的文档似乎没有描述该功能。这特殊情况可以看代码(在评论中将其描述为“疣”)。

不过,您可以在 BWK-awk 兼容模式下使用 GNU awk 获得相同的行为。

作为一种特殊情况,在兼容模式下(请参阅命令行选项部分),如果 -F 的参数为“t”,则 FS 将设置为 TAB 字符。如果您在 shell 中键入“-F\t”,不带任何引号,则“\”将被删除,因此 awk 会认为您确实希望用制表符而不是“t”分隔字段。

答案2

绝对地无论 shell/env 组合如何,最安全的方法是使用方笼和双反斜杠作为选项卡

FS='[t]'         # for just lowercase "t"
FS='[\\411]'     # for the tab "\t"

即使\\它在单引号内,即使它在单引号内,如果任何环境变得太聪明并尝试剥离其中一个,awk它仍然会作为制表符本身的底层字节。

如果你是真的对此感到偏执,然后做

FS='[\534\564]'  # for the tab "\t"

相关内容