在AWK十六进制转换为十进制或sed的

问题描述 投票:18回答:7

我有一个数字,以逗号分隔的列表:

123711184642,02,3583090366663629,639f02012437d4
123715942138,01,3538710295145500,639f02afd6c643
123711616258,02,3548370476972758,639f0200485732

我需要在第3列分成三个如下:

123711184642,02,3583090366663629,639f02,0124,37d4
123715942138,01,3538710295145500,639f02,afd6,c643
123711616258,02,3548370476972758,639f02,0048,5732

和转换数字在最后两个栏为十进制:

123711184642,02,3583090366663629,639f02,292,14292
123715942138,01,3538710295145500,639f02,45014,50755
123711616258,02,3548370476972758,639f02,72,22322
sed awk decimal hex
7个回答
23
投票

下面是对乔纳森的回答变化:

awk $([[ $(awk --version) = GNU* ]] && echo --non-decimal-data) -F, '
    BEGIN {OFS = FS}
    {
        $6 = sprintf("%d", "0x" substr($4, 11, 4))
        $5 = sprintf("%d", "0x" substr($4,  7, 4))
        $4 = substr($4,  1, 6)
        print
    }'

我包括它是否需要添加--non-decimal-data选项的相当扭曲的方式。

编辑

只是它的挫折感,这里的纯猛砸相当于:

saveIFS=$IFS
IFS=,
while read -r -a line
do
    printf '%s,%s,%d,%d\n' "${line[*]:0:3}" "${line[3]:0:6}" "0x${line[3]:6:4}" "0x${line[3]:10:4}"
done
IFS=$saveIFS

所述"${line[*]:0:3}"(引述*)的工作方式类似于AWK的OFS在于它会导致击的IFS(此处为逗号)上输出阵列元件之间插入。我们可以通过插入数组元素如下一种更接近于平行我上面的AWK版本需要该功能的另一个优点。

saveIFS=$IFS
IFS=,
while read -r -a line
do
    line[6]=$(printf '%d' "0x${line[3]:10:4}")
    line[5]=$(printf '%d' "0x${line[3]:6:4}")
    line[4]=$(printf '%s' "${line[3]:0:6}")
    printf '%s\n' "${line[*]}"
done
IFS=$saveIFS

不幸的是,猛砸不允许printf -v(这类似于sprintf())进行分配数组元素,所以printf -v "line[6]" ...不起作用。

编辑:作为猛砸4.1,printf -v现在可以进行分配给数组元素。例:

printf -v 'line[6]' '%d' "0x${line[3]:10:4}"

需要围绕阵列参考引号,以防止可能的文件名匹配。如果一个名为“LINE6”文件在当前目录中存在与参考是没有报价,那么一个变量命名line6将包含printf的输出来创建(或更新)。闲来无事有关文件,如它的内容,将开始发挥作用。只有名字 - 只有切线。


9
投票

这似乎工作:

awk -F, '{ p1 =       substr($4,  1, 6);
           p2 = ("0x" substr($4,  7, 4)) + 0;
           p3 = ("0x" substr($4, 11, 4)) + 0;
           printf "%s,%s,%s,%s,%d,%d\n", $1, $2, $3, p1, p2, p3;
         }'

为您的样品输入数据,它产生:

123711184642,02,3583090366663629,639f02,292,14292
123715942138,01,3538710295145500,639f02,45014,50755
123711616258,02,3548370476972758,639f02,72,22322

随后加入0力加“0x”加4位十六进制的字符串连接awk对待数字为十六进制数。

您可以简化这个来:

awk -F, '{ p1 =      substr($4,  1, 6);
           p2 = "0x" substr($4,  7, 4);
           p3 = "0x" substr($4, 11, 4);
           printf "%s,%s,%s,%s,%d,%d\n", $1, $2, $3, p1, p2, p3;
         }'

以0x前缀字符串被迫向printf()%d格式时为整数。


上面的代码与在MacOS X 10.6.5(版本20070501)天然awk精美的作品;可悲的是,它不与GNU gawk 3.1.7工作。也就是说,现在看来,是根据POSIX允许的行为(见下面的评论)。然而,gawk具有非标准功能strtonum可用于将它棍棒成执行正确 - 可惜钝击是必要的。

gawk -F, '{ p1 =      substr($4,  1, 6);
            p2 = "0x" substr($4,  7, 4);
            p3 = "0x" substr($4, 11, 4);
            printf "%s,%s,%s,%s,%d,%d\n", $1, $2, $3, p1, strtonum(p2), strtonum(p3);
          }'

7
投票

By AWK

这个答案集中展示了如何通过AWK可移植做转换。

使用--non-decimal-data为GAWK根据GNU Awk User's Guide不推荐。并使用strtonum()是不可移植。

在下列实施例的每个记录的第一个字被转换。

由用户定义的函数

做转换的最简便的方式是通过用户定义的函数AWK [reference]:

function parsehex(V,OUT)
{
    if(V ~ /^0x/)  V=substr(V,3);

    for(N=1; N<=length(V); N++)
        OUT=(OUT*16) + H[substr(V, N, 1)]

    return(OUT)
}

BEGIN { for(N=0; N<16; N++)
        {  H[sprintf("%x",N)]=N; H[sprintf("%X",N)]=N } }

{ print parsehex($1) }

通过调用shell的printf

您可以使用此

awk '{cmd="printf %d 0x" $1; cmd | getline decimal; close(cmd); print decimal}'

但速度相对较慢。下面一个是速度更快,如果你有很多换行分隔的十六进制数转换:

awk 'BEGIN{cmd="printf \"%d\n\""}{cmd=cmd " 0x" $1}END{while ((cmd | getline dec) > 0) { print dec }; close(cmd)}'

如果很多参数都增加了对单一printf命令有可能是一个问题。

在Linux中

在我的经验,按照Linux的作品:

awk -Wposix '{printf("%d\n","0x" $1)}'

我在Ubuntu Linux操作系统进行测试14.04它由GAWK,mawk和原始的awk。通过原始awk的命令显示一条警告消息,但您可以通过在shell重定向指令2>/dev/null隐藏它。如果你不想这样做,你可以剥除-Wposix在原始的awk这样的情况:

awk $(awk -Wversion >/dev/null 2>&1 && printf -- "-Wposix") '{printf("%d\n","0x" $1)}'

(在bash 4,你可以通过更换>/dev/null 2>&1 &>/dev/null

注:-Wposix招可能不与在OS X中使用NAWK和一些BSD操作系统变种工作,虽然。


0
投票
cat all_info_List.csv| awk 'BEGIN {FS="|"}{print $21}'| awk 'BEGIN {FS=":"}{p1=$1":"$2":"$3":"$4":"$5":";  p2 = strtonum("0x"$6); printf("%s%02X\n",p1,p2+1) }'

上述命令打印“all_info_List.csv”,一个文件,其中字段分隔符是内容的“|”。然后采取字段21(MAC地址),并且使用字段分隔符分割为“:”。将其分配给变量 “p1” 前5个字节每个MAC地址的,因此,如果我们有该MAC地址: “11:22:33:44:55:66”,p1将是:“11:22:33:44 :55:”。 p2被分配的最后一个字节的十进制值:“0x66”将会分配“102”十进制到p2。最后,我使用printf加入p1p2,而转换p2回十六进制,增加一个到它后。


0
投票

这可能会为你(GNU SED和printf的)工作:

sed -r 's/(....)(....)$/ 0x\1 0x\2/;s/.*/printf "%s,%d,%d" &/e' file

拆分最后八个字符,并添加由十六进制标识符之前的领域空间,然后评估用printf整条生产线。


0
投票
printf "%d\n", strtonum( "0x"$1 )"

-1
投票

Perl版本,用帽子@Jonathan的提示:

perl -F, -lane '$p1 = substr($F[3], 0, 6); $p2 = substr($F[3], 6, 4); $p3 = substr($F[3], 10, 4); printf "%s,%s,%s,%s,%d,%d\n", @F[0..2], $p1, hex($p2), hex($p3)' file

-a打开自动分割模式,来填充@F阵列 -F,改变自动分割隔板,(默认为空格) 的substr()指数比它们AWK当量少1,因为Perl阵列从0开始。

输出:

123711184642,02,3583090366663629,639f02,292,14292
123715942138,01,3538710295145500,639f02,45014,50755
123711616258,02,3548370476972758,639f02,72,22322
© www.soinside.com 2019 - 2024. All rights reserved.