【问题标题】:bash: oneliner to convert hex numbers in output to decimalsbash:oneliner 将输出中的十六进制数字转换为十进制
【发布时间】:2017-11-05 10:12:39
【问题描述】:

有谁知道可以将某些输出通过管道输入到bash 中的单行器,以匹配和转换所有出现的十六进制数字并保持所有其他文本不变?

  • 可能匹配相当任意的输出,可能是十六进制 应通过正则表达式以某种方式转换,即 /(0x)?[0-9a-fA-F]{5,}/
  • 前导0x 不是必需的,但是 也要妥善处理
  • 可能存在误报,如果不是 指定数字的最小长度,但这不应该是 问题
  • 我们的目标是找到可用于尽可能多的包含十六进制数字的输出的解决方案

它应该适用于如下输出:

ssg sjas # cat /proc/net/stat/arp_cache | column -t 
entries   allocs    destroys  hash_grows  lookups   hits      res_failed  rcv_probes_mcast  rcv_probes_ucast  periodic_gc_runs  forced_gc_runs  unresolved_discards  table_fulls
0000000d  00000006  00000004  00000000    0000c3b9  0000c35e  00000000    00000000          00000000          0000965b          00000000        00000000             00000000
0000000d  0000000d  00000004  00000001    00000000  00000000  00000000    00000000          00000000          000007cd          00000000        00000000             00000000
0000000d  00000008  00000008  00000001    00000000  00000000  00000000    00000000          00000000          000006e0          00000000        00000000             00000000
0000000d  0000000a  00000008  00000000    00000000  00000000  00000002    00000000          00000000          00000704          00000000        00000000             00000000

stackoverflow 上的大多数其他问题仅解决如何在数字系统之间转换单个数字的问题,仅针对指定列进行转换或完全取消输入中存在的格式。

所需的输出应如下所示:(column -t 无论如何都存在,它真的只需要替换它可以找到的十六进制值,并且在 printf 语句中添加前导零也不是问题)

ssg sjas # cat /proc/net/stat/arp_cache | perl -pe 's/(?:0x)?[0-9a-f]{5,}/hex($&)/ge' | column -t
entries  allocs  destroys  hash_grows  lookups  hits   res_failed  rcv_probes_mcast  rcv_probes_ucast  periodic_gc_runs  forced_gc_runs  unresolved_discards  table_fulls
13       6       4         0           50105    50014  0           0                 0                 38491             0               0                    0
13       13      4         1           0        0      0           0                 0                 1997              0               0                    0
13       8       8         1           0        0      0           0                 0                 1760              0               0                    0
13       10      8         0           0        0      2           0                 0                 1796              0               0                    0

在过去的两个小时内,我无法通过sed/awk/perl 找到可行/可靠的解决方案,所以我来这里寻求帮助。

【问题讨论】:

  • 请将该示例输入的所需输出添加到您的问题中。
  • 想要的输出和输入不匹配,为什么0000c1c5转换成0

标签: regex bash hex decimal converter


【解决方案1】:

perl 使用 e 标志进行替换

perl -pe 's/(0x)?[0-9a-f]{5,}/hex $&/ge' file | column -t

【讨论】:

    【解决方案2】:

    带有自动拆分开关的perl:

    perl -anE'say join " ", map {/(?:0x)?([0-9a-f]{5,})/i ? hex $1 : $_} @F' file | column -t
    

    -n 开关提供了对文件行的隐式循环。

    -E 开关提供可选功能,例如say 命令(用于打印带有自动回车的内容)。 -E 也与执行参数中给出的代码的 -e 开关做同样的事情(而不是寻找要启动的文件)。

    -a 开关(自动拆分)在空白处分割每一行,并用各个部分填充 @F 数组(就像 awk 一样)。

    map { } @F 处理@F 的每个元素并返回一个新数组。

    /(?:0x)?([0-9a-f]{5,})/i ? hex($1) : $_ 使用三元运算符condition ? true : false。当模式匹配时,它返回转换后的捕获组 1,而不是原始部分。

    请注意,Perl 是一种考虑上下文的​​语言。 map {} 中的$_ 指的是@F 项目,/(?:0x)?([0-9a-f]{5,})/i$_ =~ /(?:0x)?([0-9a-f]{5,})/i 的简称。 map {} 之外的$_ 是当前行)

    【讨论】:

    • @sjas:不,我的错@123 答案是正确的,因为print hex "0x10" (这次引用) 按预期返回16。你应该接受他的回答,而不是我的回答
    • @CasimiretHippolyte:感谢您提供的出色代码,能否请您也添加解释,我是 perl 的初学者。
    • @RavinderSingh13:我在回答中添加了更多细节,但最好使用 Perl 文档:perldoc perlrunman perlrun 或在线文档。
    • 仍然感谢您的出色表现。 :)
    【解决方案3】:

    很抱歉给您带来了困惑。这是使用 bash 的该功能的单行代码:

    cat /proc/net/stat/arp_cache | sed -e '2,$s/\s*\([0-9a-f][0-9a-f]*\)\s*/ \$\(\( 0x\1 \)\) /g' -e 's/^/echo /' | bash | column -t
    entries  allocs  destroys  hash_grows  lookups  hits  res_failed  rcv_probes_mcast  rcv_probes_ucast  periodic_gc_runs  forced_gc_runs  unresolved_discards  table_fulls
    8        2       0         0           0        0     0           0                 0                 0                 0               0                    0
    8        0       0         0           211      58    0           0                 0                 0                 0               0                    0
    8        2       0         0           6319     1677  0           0                 0                 3882              0               0                    0
    8        4       0         0           4731     1299  0           0                 0                 0                 0               0                    0
    

    【讨论】:

    • 您确实添加了另一个答案并自己添加了一条评论,表示您喜欢您的新答案?那只是“嗯”。
    • 没有。我正在回复另一条评论(现在显然已删除),建议我将 > tmp$$ && source ./tmp$$ 替换为 | bash。我猜他决定删除他的评论,因为我根据他的建议编辑了我的答案。
    • 不错。为你 +1。
    【解决方案4】:

    使用mawk:除第一行以外的每一行 (NR!=1) 从第一列到最后一列 (NF) 循环并将当前列 ($i) 从十六进制转换为十进制。

    mawk 'NR!=1 {for (i=1; i<=NF; i++) $i=sprintf("%d ","0x"$i)}1' file | column -t
    

    输出:

    条目 allocs 破坏 hash_grows 查找命中 res_failed rcv_probes_mcast rcv_probes_ucast period_gc_runs force_gc_runs unresolved_discards table_fulls 13 6 4 0 49696 49605 0 0 0 38201 0 0 0 13 13 4 1 0 0 0 0 0 1984 0 0 0 13 8 8 1 0 0 0 0 0 1752 0 0 0 13 10 8 0 0 0 2 0 0 1775 0 0 0

    【讨论】:

      【解决方案5】:

      GNU awk:

      awk 'BEGIN{IFS=OFS="\t"}NR==1{print $0}{for(i=1;i<=NF;i++) if(i!=NF){printf "%s%c",strtonum("0x"$i),OFS}else{printf "%d\n",strtonum("0x"$i)}}' filename
      

      【讨论】:

      • 这与我已经拥有的非常相似,但没有按预期工作。 IE。 0000000d 被转换为 0 而不是 13
      【解决方案6】:

      前导0 被认为是八进制,前导0x 被认为是十六进制。如果您的数字符合该标准,那么$(( &lt;number&gt; )) 会将它们转换为十进制:

      $ echo $(( 0x1b ))
      27
      $ echo $(( 014 ))
      12
      

      【讨论】:

      • 这显然不是关于转换孤独的数字,而是完整的输出。
      猜你喜欢
      • 1970-01-01
      • 2015-01-26
      • 1970-01-01
      • 1970-01-01
      • 2011-07-28
      • 1970-01-01
      相关资源
      最近更新 更多