当使用AWK时,我很难理解为什么不存在的字段(后面的字段$NF)不等于等于数字零.
在下面的示例中,输入行有两个字段,因此根据规范$3应该是"未初始化的值"并且比较等于0.换句话说,$3 == 0应该返回true,但正如您在下面看到的那样它返回false:
$ echo '1 2' | awk '{ print($3 == 0 ? "t" : "f") }'
f
Run Code Online (Sandbox Code Playgroud)
"One True AWK"(版本20121220)和GNU AWK(版本4.2.1)的行为方式相同.这是GNU AWK输出:
$ echo '1 2' | gawk '{ print($3 == 0 ? "t" : "f") }'
f
Run Code Online (Sandbox Code Playgroud)
根据POSIX AWK规范,不存在的字段$3应该是未初始化的值:
对不存在的字段(即$ NF之后的字段)的引用应评估为未初始化的值.
此外,==如果一个操作数是数字而另一个是未初始化的值,则应该以数字方式进行比较:
比较(使用'<',"<=","!=","==",">"和"> ="运算符)如果两个操作数都是数字,则应以数字方式进行比较,如果一个是数字,则other的字符串值是数字字符串,或者如果一个是数字而另一个是未初始化的值.否则,操作数应根据需要转换为字符串......
最后,未初始化的值的"数值"应为零:
未初始化的值应具有零值的数值和空字符串的字符串值.
将此与未初始化的变量进行对比,该变量的确比较等于零:
$ awk 'BEGIN { print(x == 0 ? "t" : "f") }'
t
Run Code Online (Sandbox Code Playgroud)
所以在我们的第一个例子中,$3应该是一个未初始化的值,==应该用数字比较它,它的数值应该是零.因此在我看来$3 == 0 ? "t" : "f"应该输出t而不是f.
任何人都可以帮助我理解为什么它没有,或者帮助我看看我是如何误读规范的?
有一个有趣的通道awk编程语言中由阿尔弗雷德V.阿霍,布赖恩W. Kernighan和彼得·温伯格(1988)(在这里预订):
使用数值0和字符串值创建未初始化的变量
"".不存在的字段和显式为null的字段只有字符串值""; 它们不是数字,但是当强制转换为数字时,它们会获得数值0.
此外:
未初始化的变量具有数值
0和字符串值"".因此,如果x是未初始化的,Run Code Online (Sandbox Code Playgroud)if (x) ...是假的,而且
Run Code Online (Sandbox Code Playgroud)if (!x) ... if (x == 0) ... if (x == "") ...都是真的.但请注意
Run Code Online (Sandbox Code Playgroud)if (x == "0") ...是假的.
字段的类型在可能的情况下由上下文确定; 例如,
$1++意味着,$1如果有必要,必须强制转换为数字,并$1 = $1 "," $2暗示$1,并$2在必要时将被强制转换为字符串.在无法可靠地确定类型的情况下,例如,
Run Code Online (Sandbox Code Playgroud)if {$1 == $2) ...每个字段的类型根据输入确定.所有字段都是字符串 ; 此外,仅包含数字的每个字段也被视为数字.显式为null的字段具有字符串值
""; 它们不是数字.不存在的字段(即字段过去NF)和$0空行也是这样处理的.因为它是字段,所以它是由创建的数组元素
split.
在我看来,这些行很好地解释了观察到的行为,似乎大多数程序也遵循这一点.
在调查GNU Awk 4.2.1的源代码时,我发现:
未初始化的变量被赋值Node为Nnull_string具有标志的named :
main.c: Nnull_string->flags = (MALLOC|STRCUR|STRING|NUMCUR|NUMBER);
Run Code Online (Sandbox Code Playgroud)不存在的字段被分配给名为的节点Null_field,该节点被重新定义Nnull_string为:
field.c: *Null_field = *Nnull_string;
field.c: Null_field->valref = 1;
field.c: Null_field->flags = (STRCUR|STRING|NULL_FIELD); /* do not set MALLOC */
Run Code Online (Sandbox Code Playgroud)字段具有值(from awk.h):
# define STRING 0x0002 /* assigned as string */
# define STRCUR 0x0004 /* string value is current */
# define NUMCUR 0x0008 /* numeric value is current */
# define NUMBER 0x0010 /* assigned as number */
# define NULL_FIELD 0x2000 /* this is the null field */
Run Code Online (Sandbox Code Playgroud)
比较功能int cmp_nodes(NODE *t1, NODE *t2, bool use_strcmp)中所定义eval.c,只是检查,如果NUMBER标志被设置两者t1和t2:
if ((t1->flags & NUMBER) != 0 && (t2->flags & NUMBER) != 0)
return cmp_numbers(t1, t2);
Run Code Online (Sandbox Code Playgroud)
由于Null_field没有数字字段,它只是假设它代表一个字符串.这一切似乎都与本书引用的内容一致!
此外,来自awk.h:
* STRING and NUMBER are mutually exclusive, except for the special
* case of an uninitialized value, represented internally by
* Nnull_string. They represent the type of a value as assigned.
* Nnull_string has both STRING and NUMBER attributes, but all other
* scalar values should have precisely one of these bits set.
*
* STRCUR and NUMCUR are not mutually exclusive. They represent that
* the particular type of value is up to date. For example,
*
* a = 5 # NUMBER | NUMCUR
* b = a "" # Adds STRCUR to a, since a string value
* # is now available. But the type hasn't changed!
*
* a = "42" # STRING | STRCUR
* b = a + 0 # Adds NUMCUR to a, since numeric value
* # is now available. But the type hasn't changed!
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
267 次 |
| 最近记录: |