在awk或sed中将十六进制转换为十进制
我有一个以逗号分隔的数字列表:在awk或sed中将十六进制转换为十进制,sed,awk,decimal,hex,Sed,Awk,Decimal,Hex,我有一个以逗号分隔的数字列表: 123711184642,02,3583090366663629,639f02012437d4 123715942138,01,3538710295145500,639f02afd6c643 123711616258,02,3548370476972758,639f0200485732 我需要将第三列拆分为三列,如下所示: 123711184642,02,3583090366663629,639f02,0124,37d4 123715942138,01,3538
123711184642,02,3583090366663629,639f02012437d4
123715942138,01,3538710295145500,639f02afd6c643
123711616258,02,3548370476972758,639f0200485732
我需要将第三列拆分为三列,如下所示:
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
123711184642,02,3583090366663629,639f02,292,14292
123715942138,01,3538710295145500,639f02,45014,50755
123711616258,02,3548370476972758,639f02,72,22322
这似乎有效:
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
“0x”加上4位十六进制再加上0的字符串串联迫使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;
}'
当显示为printf()
和%d
格式时,前缀为0x的字符串被强制为整数
上面的代码与MacOS X 10.6.5(版本20070501)上的本机
awk
配合得很好;遗憾的是,它不适用于GNUgawk
3.1.7。根据POSIX,这似乎是允许的行为(见下面的评论)。但是,gawk
有一个非标准函数strotnum
,可以用来强迫它正确执行-遗憾的是,强迫是必要的
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);
}'
以下是乔纳森答案的一个变体:
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
}'
如果需要的话,我加入了一种相当扭曲的方式来添加选项
编辑
只是为了见鬼,这里有一个纯Bash等价物:
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
,因为它会导致在输出时在数组元素之间插入Bash的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
不幸的是,Bash不允许printf-v
(类似于sprintf()
)对数组元素进行赋值,因此printf-v“line[6]”不起作用
编辑:从Bash4.1开始,printf-v
现在可以对数组元素进行赋值。例如:
printf -v 'line[6]' '%d' "0x${line[3]:10:4}"
需要在数组引用周围加引号,以防止可能的文件名匹配。如果当前目录中存在名为“line6”的文件且引用未被引用,则将创建(或更新)一个名为line6
的变量,其中包含printf输出。关于该文件的任何其他内容,例如其内容,都不会起作用。只有名字-而且只有切线
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地址),并使用字段分隔符“:”将其拆分。
它将每个mac地址的前5个字节分配给变量“p1
”,因此如果我们有这个mac地址:“11:22:33:44:55:66”,p1
将是:“11:22:33:44:55:”。
p2
被分配最后一个字节的十进制值:“0x66”将为p2
分配“102”十进制值。
最后,我使用printf
连接p1
和p2
,同时将p2
转换回十六进制,然后再向其中添加一个
这个答案集中于展示如何通过可移植的awk进行转换
根据,不建议使用--非十进制数据进行gawk。并且使用strtonum()
是不可移植的
在以下示例中,将转换每条记录的第一个字
按用户定义的函数
进行转换的最方便的方法是使用用户定义的awk函数[]:
但这是相对缓慢的。如果要转换多个换行分隔的十六进制数,则下面的转换速度更快:
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)}'
我在UbuntuLinux14.04中通过gawk、mawk和原始awk对其进行了测试。通过原始awk,该命令显示一条警告消息,但您可以通过shell中的重定向指令2>/dev/null
将其隐藏。如果您不想这样做,您可以在原始awk的情况下剥离-Wposix
,如下所示:
awk $(awk -Wversion >/dev/null 2>&1 && printf -- "-Wposix") '{printf("%d\n","0x" $1)}'
(在Bash4中,您可以用&>/dev/null
替换>/dev/null>&1
)
注意,-Wposix技巧可能不适用于在OS X和某些BSD OS变体中使用的nawk。这可能适用于您(GNU-sed&printf):
拆分最后八个字符,并在字段前面添加空格(十六进制标识符),然后使用printf对整行进行求值。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,023583090366663629639F02,0,0 123715942138,01358710295145500639F02,0,0 123711616258,02354837047972758639F02,0,0哪个平台上的awk
?我正在使用MacOS X 10.6.5及其awk版本20070501;当我使用Gawk3.1.7时,它会给出零。这值得向GNU报告一次错误。我将研究一种变通方法……我在使用GNU Awk 3.1的Redhat Linux 2.6和SunOS 5.10上获得了类似的结果。5@bernie:如果使用--非十进制数据
选项,第一个版本将与gawk
一起使用。POSIX说它是特定于实现的。@bernie:我删除了一个错误的sprintf
到数组的printf-v
我相信bash4.1中添加了元素,做得很好;值得将2>/dev/null
添加到awk--version
,因为mawk
将打印带有--version
的错误消息。根据建议,不建议使用--non-decimal data
。或者,添加-Wposix
选项似乎适用于所有适用于Ubuntu Linux的awk实现,即mawk、gawk和original-awk。尽管-Wposix
可能不适用于OSX和某些BSD操作系统中使用的nawk,如本.s中所述
sed -r 's/(....)(....)$/ 0x\1 0x\2/;s/.*/printf "%s,%d,%d" &/e' file
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
123711184642,02,3583090366663629,639f02,292,14292
123715942138,01,3538710295145500,639f02,45014,50755
123711616258,02,3548370476972758,639f02,72,22322
printf "%d\n", strtonum( "0x"$1 )"