我有 awk 的 gawk 版本。在这gawk手册的一部分指出awk变量具有“属性”,用于确定在各种操作中如何处理它们。
例如," +3.14"
通过解析输入获得的形式的字符串具有该STRNUM
属性,这使得它在与数字比较时表现为数字,而 awk 程序中定义的同一字符串不具有该属性。
OTOH,像这样的字符串"3.14"
显然具有STRNUM
属性,即使它是在程序中定义的,因为代码x = "3.14" { print x == 3.14 }
打印 1。而如果我们将其定义为"+3.13"
or " 3.14"
,它就没有STRNUM
属性,因为x = "+3.14" { print x == 3.14 }
orx = " 3.14" { print x == 3.14 }
打印 0。
我认为变量类型的这种简洁性可能会导致微妙的错误。因此,为了帮助调试这种情况,有没有办法了解变量具有什么类型的“属性”?即,我们能知道变量的类型是什么吗?
答案1
awk 有4种:“数字”、“字符串”、“数字字符串”和“未定义”。这是一个函数检测到:
function o_class(obj, q, x, z) {
q = CONVFMT
CONVFMT = "% g"
split(" " obj "\1" obj, x, "\1")
x[1] = obj == x[1]
x[2] = obj == x[2]
x[3] = obj == 0
x[4] = obj "" == +obj
CONVFMT = q
z["0001"] = z["1101"] = z["1111"] = "number"
z["0100"] = z["0101"] = z["0111"] = "string"
z["1100"] = z["1110"] = "strnum"
z["0110"] = "undefined"
return z[x[1] x[2] x[3] x[4]]
}
对于 的第三个参数split
,您需要的不是空格,也不是 的一部分,obj
否则它将被视为分隔符。我选择\1
基于斯蒂芬的建议。该函数进行内部CONVFMT
切换,因此无论CONVFMT
函数调用时的值如何,它都应该返回正确的结果:
split("12345.6", q); print 1, o_class(q[1])
CONVFMT = "%.5g"; split("12345.6", q); print 2, o_class(q[1])
split("nan", q); print 3, o_class(q[1])
CONVFMT = "%.6G"; split("nan", q); print 4, o_class(q[1])
结果:
1 strnum
2 strnum
3 strnum
4 strnum
完整的测试套件:
print 1, o_class(0)
print 2, o_class(1)
print 3, o_class(123456.7)
print 4, o_class(1234567.8)
print 5, o_class(+"inf")
print 6, o_class(+"nan")
print 7, o_class("")
print 8, o_class("0")
print 9, o_class("1")
print 10, o_class("inf")
print 11, o_class("nan")
split("00", q); print 12, o_class(q[1])
split("01", q); print 13, o_class(q[1])
split("nan", q); print 14, o_class(q[1])
split("12345.6", q); print 15, o_class(q[1])
print 16, o_class()
结果:
1 number
2 number
3 number
4 number
5 number
6 number
7 string
8 string
9 string
10 string
11 string
12 strnum
13 strnum
14 strnum
15 strnum
16 undefined
值得注意的弱点是:如果您提供以下任何一个“数字字符串”,该函数将错误地返回“数字”:
- 整数
inf
-inf
对于整数,解释如下:
完全等于整数值的数值应通过等效于以
sprintf
字符串%d
作为fmt
参数调用函数来转换为字符串
然而,inf
也-inf
应该这样做;也就是说,上述各项都不会受到该CONVFMT
变量的影响:
CONVFMT = "% g"
print "" .1
print "" (+"nan")
print "" 1
print "" (+"inf")
print "" (+"-inf")
结果:
0.1
nan
1
inf
-inf
实际上这并不重要,请参阅鸭子测试。
答案2
从 GNU Awk 4.2 开始,有一个新函数typeof()
可以检查这一点,如测试版本的发行说明中所示:
- 新的 typeof() 函数可用于指示变量或数组元素是否为数组、正则表达式、字符串或数字。 isarray() 函数已被弃用,取而代之的是 typeof()。
所以现在你可以说:
$ awk 'BEGIN {print typeof("a")}'
string
$ awk 'BEGIN {print typeof(1)}'
number
$ awk 'BEGIN {print typeof(a[1])}'
unassigned
$ awk 'BEGIN {a[1]=1; print typeof(a)}'
array
$ echo ' 1 ' | awk '{print typeof($0)}'
strnum
答案3
答案4
如果gawk < 4.2(RHEL7默认版本:gawk 4.0.2)
作为 fedorqui 答案和 gawk 4.2发行公告
14. 新的 typeof() 函数可用于指示变量或数组元素是否为数组、正则表达式、字符串或数字。
$ cat test.txt
11.11
-0
ext4
0
xfs
0.123
11111.111111
-3333.3333333
$ cat test.txt | awk '{if($1!=0 && $1+0==0) {print $1" non-numeric"} else {print $1" numeric"} }'
11.11 numeric
-0 numeric
ext4 non-numeric
0 numeric
xfs non-numeric
0.123 numeric
11111.111111 numeric
-3333.3333333 numeric
如果呆呆> = 4.2
$ cat test.txt | awk '{{print $1" ,"typeof($1)}}'
11.11 ,strnum
-0 ,strnum
ext4 ,string
0 ,strnum
xfs ,string
0.123 ,strnum
11111.111111 ,strnum
-3333.3333333 ,strnum