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 :(得分:5)
你在这里处理两个相似但不同的问题,awk
输入中的非十进制数据和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(可能是你正在使用nawk
或mawk
)表现得“正确”。 gawk
(自版本3.1起)默认支持非十进制(八进制和十六进制)文字数字,但使用--posix
开关将其关闭,如预期的那样。
在这种情况下的正常解决方法是使用定义的数字字符串行为,其中数字字符串将被有效地解析为C标准atof()
或strtod()
函数,支持0x
- 前缀数字:
$ 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
更新:gawk
的目标是“2008 POSIX.1003.1”,但请注意,因为2008版(请参阅IEEE Std 1003.1 2013 edition awk
here)允许strtod()
和实现相关的行为不需要数字符合词汇约定。这应该(隐含地)支持INF
和NAN
。类似地修改了词汇约定中的文本,以选择性地允许带有0x
前缀的十六进制常量。
gawk
完全不希望这种行为(考虑到数字的词汇限制):
$ echo "0x14" | gawk '$1+1<=0x15 {print $1+1}'
1
(注意“错误的”数字答案,|wc -l
会隐藏它
除非你也使用--non-decimal-data
:
$ echo "0x14" | gawk --non-decimal-data '$1+1<=0x15 {print $1+1}'
21
另见:
此SE question的已接受答案具有可移植性解决方法。
对非十进制数有两种支持的选项是:
gawk
,不使用--posix
和使用--non-numeric-data
如果您搜索“awk dec2hex”,您可以找到后者的许多实例,这里有一个可通行的实例:http://www.tek-tips.com/viewthread.cfm?qid=1352504。如果您想要gawk的strtonum()
之类的内容,则可以获得仅支持awk的移植版here。
答案 1 :(得分:1)
您是否仍然使用旧的awk
版本?我不知道用十六进制数字做数学的方法(你将不得不等待更好的答案:-)。我可以选择Gawk
:
-n, - non-decimal-data:识别输入数据中的八进制和十六进制值。请谨慎使用此选项!
所以,
echo "0x14" | awk -n '$1+1<=21 {print $1+1}'
和
echo "0x14" | awk -n '$1+1<=0x15 {print $1+1}'
返回
21
答案 2 :(得分: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(),只要你有一个十六进制数字:
$ 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