【问题标题】:awk version issue - convert hex to decimalawk 版本问题 - 将十六进制转换为十进制
【发布时间】:2011-12-25 20:11:08
【问题描述】:

我通常在我的 Mac 上编写脚本,然后一旦准备好,我就会将它们发送到我工作时的测试盒中。我在这里面临的问题是我有一个数据流,它是十六进制格式的 IP 地址。我正在使用 sed 和 awk 的组合来解析它并将其转换为更易读的格式。

$echo $content12
cb5c860100000000000000000000000000 

[DoD@MBP-13~] echo $content12 | 
sed -e 's/../&./g' -e 's/.$//' | sed 's/[0-9a-z][0-9a-z]/0x&/g' | 
awk -F"." '{for (i=1;i<NF;i++) printf ("%d\n", $i)}' |
awk '{if (NR<5) printf $0; printf "."}' | sed 's/\.\.*$//'
203.92.134.1 

当我在工作中将它移植到我的测试盒时,脚本没有按预期工作。

$echo $content12 | 
sed -e 's/../&./g' -e 's/.$//' | sed 's/[0-9a-z][0-9a-z]/0x&/g' | 
awk -F"." '{for (i=1;i<NF;i++) printf ("%d\n", $i)}' | 
awk '{if (NR<5) printf $0; printf "."}' | sed 's/\.\.*$//'
0.0.0.0

我的 Mac 上的 awk 和 uname 版本 -

[DoD@MBP-13~] awk --version
awk version 20070501

[DoD@MBP-13~] uname -a
Darwin MBP-13.local 11.2.0 Darwin Kernel Version 11.2.0: Tue Aug  9 20:54:00 PDT 2011;     
root:xnu-1699.24.8~1/RELEASE_X86_64 x86_64

工作中我的测试盒上的 awk 和 uname 版本 -

$ awk --version
GNU Awk 3.1.5
Copyright (C) 1989, 1991-2005 Free Software Foundation

$uname -a
Linux 2.6.18-194.el5 #1 SMP Tue Mar 16 21:52:39 EDT 2010 
x86_64 x86_64 x86_64 GNU/Linux

这是我可以通过小的改动来解决的问题吗?我对 UNIX 环境还很陌生,所以我的单行代码对您来说可能看起来异常长。任何建议将不胜感激。

【问题讨论】:

    标签: parsing bash sed awk


    【解决方案1】:

    您可以使用gawk--non-decimal-data 选项使其处理输入中的八进制和十六进制数字:

    $ echo 0x10 | gawk --non-decimal-data '{ printf "%d", $1 }'
    16
    

    对比:

    $ echo 0x10 | gawk '{ printf "%d", $1 }'
    0
    

    【讨论】:

      【解决方案2】:

      本质上,这个问题归结为给printf提供一个参数字符串。printf是一个内置的shell,所以:

      echo "cb5c860100000000000000000000000000" |
      sed 's/\(.\{8\}\).*/\1/;s/../"0x&" /g;s/^/printf "%d.%d.%d.%d\n" /'|sh
      203.92.134.1
      

      在 GNU sed 中,您可以评估模式空间,如下所示:

      echo "cb5c860100000000000000000000000000" |
      sed 's/\(.\{8\}\).*/\1/;s/../"0x&" /g;s/^/printf "%d.%d.%d.%d" /e'
      203.92.134.1
      

      在编程中,我发现最难的不是编码,而是说出你的意思。

      【讨论】:

        【解决方案3】:

        显然 GNU awk(1) 实现不会将 0x11 作为 printf() 的参数处理:

        $ echo cb5c860100000000000000000000000000 | sed -e 's/../&./g' -e 's/.$//' |
          sed 's/[0-9a-z][0-9a-z]/0x&/g'
        0xcb.0x5c.0x86.0x01.0x00.0x00.0x00.0x00.0x00.0x00.0x00.0x00.0x00.0x00.0x00.0x00.0x00
        $ echo cb5c860100000000000000000000000000 | sed -e 's/../&./g' -e 's/.$//' |
          sed 's/[0-9a-z][0-9a-z]/0x&/g' |
          awk -F"." '{for (i=1;i<NF;i++) printf ("%d\n", $i)}'
        0
        0
        0
        ...
        

        mawk(1) 安装在我的系统上(由 Mike Brennan 编写)—— GNU awk(1) 的替代品,声称更小、更快并且仍然符合 POSIX 1003.2(草案 11.3)——确实 em> 按照你的预期解释:

        $ echo cb5c860100000000000000000000000000 | sed -e 's/../&./g' -e 's/.$//' |
          sed 's/[0-9a-z][0-9a-z]/0x&/g' |
          mawk -F"." '{for (i=1;i<NF;i++) printf ("%d\n", $i)}' |
          mawk '{if (NR<5) printf $0; printf "."}' | sed 's/\.\.*$//'
        203.92.134.1$ 
        

        如果您有幸还安装了mawk(1) 并且可用,那么此解决方案可能是合适的。

        【讨论】:

        • 谢谢萨诺德。不幸的是,我没有在我的测试盒上安装它。我必须与系统管理员联系才能部署它。我使用了@Rick 的答案,因为它很容易实现。
        • 我也喜欢@Rick 的回答,它的破坏性远小于我的。当我看到他的回答时,我正忙着阅读gawk(1) 联机帮助页试图弄清楚如何使用CONVFMT,所以我当时就放弃了。 :)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-04
        • 2011-07-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多