2013-10-22 82 views
4

AWK能够解析领域的十六进制数字:十六进制文字

$ echo "0x14" | awk '{print $1+1}' 
21 <-- correct, since 0x14 == 20 

然而,它似乎并没有与十六进制文字处理措施:

$ echo "0x14" | awk '$1+1<=21 {print $1+1}' | wc -l 
1 <-- correct 
$ echo "0x14" | awk '$1+1<=0x15 {print $1+1}' | wc -l 
0 <-- incorrect. awk is not properly handling the 0x15 here 

有没有解决办法?

+0

可能的重复:http://stackoverflow.com/questions/3683110/how-to-make-calculations-on-hexadecimal-numbers-with-awk –

+2

@RobertoNavarro完全不同的问题。我在询问如何直接在awk命令中使用十六进制字面值(如第三个awk命令所示) – SheetJS

+0

我一直在尝试不同的变体,如果你愿意,可以嘲笑这个,但是以为我会在我点击之前发布它去睡觉:bash $ hex = 20; echo $((16#$ hex + 1))| echo'0x''awk'{printf“%x \ n”,$ 1;}'' –

回答

5

你在这里处理两个相似但不同的问题,非十进制数据和非 - 您的awk计划中的文字文字。

the POSIX-1.2004 awk specification词法约定

8. The token NUMBER shall represent a numeric constant. Its form and numeric value [...] 
    with the following exceptions: 
    a. An integer constant cannot begin with 0x or include the hexadecimal digits 'a', [...] 

所以AWK(假设你使用nawkmawk)的行为 “正确”。 gawk(自版本3.1开始)默认情况下支持非十进制(八进制和十六进制)文字编号,但使用--posix开关会将其关闭,如预期的那样。

在这样的情况下正常的解决方法是使用所定义的数字串行为,其中一个数字串是有效地被解析为C标准atof()strtod()功能,支持0x -prefixed号码:

$ echo "0x14" | nawk '$1+1<=0x15 {print $1+1}' 
<no output> 
$ echo "0x14" | nawk '$1+1<=("0x15"+0) {print $1+1}' 
21 

这里的问题是,这种说法并不正确,因为POSIX-1.2004 also states

A string value shall be considered a numeric string if it comes from one of the following: 
    1. Field variables 
    ... 
and after all the following conversions have been applied, the resulting string would 
lexically be recognized as a NUMBER token as described by the lexical conventions in Grammar 

UPDATE:gawk旨在“2008 POSIX.1003。1“,但请注意,自2008版(请参阅IEEE Std 1003.1 2013 edition awk here)允许strtod()和实现相关的行为不需要数字符合词汇约定,这应该(隐含地)支持INFNAN中的文本Lexical约定同样修改,以便允许在十六进制常量与0x前缀

这不会表现(上给出的数字词汇约束)相当的希望在gawk

$ echo "0x14" | gawk '$1+1<=0x15 {print $1+1}' 
1 

(注意是“错误的”数字a nswer,这已被隐藏通过|wc -l) 除非你使用--non-decimal-data太:

$ echo "0x14" | gawk --non-decimal-data '$1+1<=0x15 {print $1+1}' 
21 

参见:

此接受了答案,这SE question有一个可移植性的解决方法。

为具有两种类型的用于非十进制数字支持的选项是:

如果你搜索“AWK DEC2HEX”你可以找到后者的许多情况下,可通过一个在这里使用。如果你想要像gawk的strtonum()这样的东西,你可以得到一个便携式awk版本here

+0

非常翔实!原来'(“0x15”+0)'在这里工作。它是否也在gawk中工作(不带-n) – SheetJS

+1

没有任何选项,否:对于转换,它被视为“0”,然后是非十进制垃圾,因此在数字上为0.如果使用“--posix”,那么它可以工作,有点奇怪。还有什么奇怪的是'-n'也使它工作。这可能是gawk/awk/POSIX的沙漏角落之一。 (对于奖励积分:gawk-3.0.4中有一个错误,它在将“0x15”转换为十进制时导致1.3125(即21/16)...) –

1

您是否陷入旧版awk版本?我不知道有什么方法可以用它来做十六进制数字的数学(你将不得不等待更好的答案:-)。我可以选择Gawk

-n, - 非十进制数据:识别输入数据中的八进制和十六进制值。谨慎使用此选项!

所以,要么

echo "0x14" | awk -n '$1+1<=21 {print $1+1}' 

echo "0x14" | awk -n '$1+1<=0x15 {print $1+1}' 

回报

21 
+1

我不使用gnu awk,不幸的是'-n'选项不是可用,但让我困惑的是,我的版本清楚地分析了输入数据中的十六进制文字(如第一个命令“echo”0x14“| awk'{print $ 1 + 1}')所示。 – SheetJS

+0

@Nirk:但是,该命令不适用于我的版本(** GNU Awk 4.1.0 **)。它返回'1'。我只知道'gawk'的解决方法。抱歉。 – Birei

+0

现在这真的很有趣。我希望GNU版本能够做到“正确的事情”。尽管如此,我从中学到了一些东西,所以得到了赞扬:) – SheetJS

1

你使用任何AWK好像是坏了,或者非POSIX至少包括:

$ echo '0x14' | /usr/xpg4/bin/awk '{print $1+1}' 
1 
$ echo '0x14' | nawk '{print $1+1}' 
1 
$ echo '0x14' | gawk '{print $1+1}' 
1 
$ echo '0x14' | gawk --posix '{print $1+1}' 
1 

获取GNU AWK和使用strtonum()无处不在,你可以有一个十六进制数字:在awk输入

$ echo '0x14' | gawk '{print strtonum($1)+1}' 
21 
$ echo '0x14' | gawk 'strtonum($1)+1<=21{print strtonum($1)+1}'    
21 
$ echo '0x14' | gawk 'strtonum($1)+1<=strtonum(0x15){print strtonum($1)+1}' 
21 
+1

我不认为你读过这个问题。 '$ echo“0x14”| awk'{print $ 1 + 1}''工作得很好。问题出现在模式中使用十六进制文字(就像在第三种情况下 - 如果十六进制文字正常工作,然后'$ echo“0x14”| awk'$ 1 + 1 <= 0x15 {print $ 1 + 1}'| wc -l'会是1,而不是0) – SheetJS

+0

我没有读过这个问题,重点是'echo“0x14”| awk'{print $ 1 + 1}''不能与你的awk“工作”。它产生你期望/希望的输出,但这不是正确的输出。所有其他的awk,包括我测试过的两个不同的POSIX awk,产生相同的输出,并且在它们自己处理一个十六进制数字字符串(它是一个字符串,而不是数字)时是一致的。产生一个人认为它应该产生的输出并不意味着它能够工作,特别是当它在某些情况下的行为仅仅如你所期望的那样。 –

+0

@SheetJS这是因为最初的问题也有点令人困惑......(至少是IMO)我也不得不读两遍才能弄清楚OP实际上在做些什么。我甚至在本地攻击了这里的行,以了解哪个输出是预期的,哪些不是。根据我的定义,“Clarity”将会是别的东西;) – syntaxerror