我有一个以逗号分隔的数字列表:
123711184642,02,3583090366663629,639f02012437d4
123715942138,01,3538710295145500,639f02afd6c643
123711616258,02,3548370476972758,639f0200485732
我需要将第3列拆分为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
答案 0 :(得分:22)
答案 1 :(得分: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
字符串连接'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
完美配合;遗憾的是,它不适用于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);
}'
答案 2 :(得分:6)
这个答案专注于展示如何通过awk进行转换。
根据GNU Awk User's Guide,建议不要使用--non-decimal-data
进行gawk。使用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) }
你可以用这个
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:
awk -Wposix '{printf("%d\n","0x" $1)}'
我在Ubuntu Linux 14.04中用gawk,mawk和original-awk测试过它。通过original-awk,该命令会显示一条警告消息,但您可以通过shell中的重定向指令2>/dev/null
将其隐藏。如果您不想这样做,可以在原始awk的情况下删除-Wposix
:
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和某些BSD OS变体中使用的nawk。
答案 3 :(得分: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
”分配给每个mac地址的前5个字节,所以如果我们有这个mac地址:“11:22:33:44:55:66”,p1
将是: “11:22:33:44:55:”。
p2
被赋予最后一个字节的十进制值:“0x66”会将“102”十进制分配给p2
。
最后,我正在使用printf
加入p1
和p2
,同时在向其添加一个后将p2
转换回十六进制。
答案 4 :(得分:0)
这可能适合你(GNU sed&amp; printf):
sed -r 's/(....)(....)$/ 0x\1 0x\2/;s/.*/printf "%s,%d,%d" &/e' file
拆分最后八个字符,并使用十六进制标识符在字段前面添加空格,然后使用printf评估整行。
答案 5 :(得分:0)
printf "%d\n", strtonum( "0x"$1 )"
答案 6 :(得分:-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,
将autosplit分隔符更改为,
(默认为空格)
substr()
索引比其awk等价物少1,因为Perl数组从0开始。
输出:
123711184642,02,3583090366663629,639f02,292,14292
123715942138,01,3538710295145500,639f02,45014,50755
123711616258,02,3548370476972758,639f02,72,22322