ber*_*nie 19 awk hex sed decimal
我有一个以逗号分隔的数字列表:
123711184642,02,3583090366663629,639f02012437d4
123715942138,01,3538710295145500,639f02afd6c643
123711616258,02,3548370476972758,639f0200485732
Run Code Online (Sandbox Code Playgroud)
我需要将第3列拆分为3,如下所示:
123711184642,02,3583090366663629,639f02,0124,37d4
123715942138,01,3538710295145500,639f02,afd6,c643
123711616258,02,3548370476972758,639f02,0048,5732
Run Code Online (Sandbox Code Playgroud)
并将最后两列中的数字转换为十进制:
123711184642,02,3583090366663629,639f02,292,14292
123715942138,01,3538710295145500,639f02,45014,50755
123711616258,02,3548370476972758,639f02,72,22322
Run Code Online (Sandbox Code Playgroud)
Pau*_*ce. 24
以下是乔纳森答案的变体:
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
}'
Run Code Online (Sandbox Code Playgroud)
如果需要的话,我提供了一种相当扭曲的添加--non-decimal-data选项的方法.
编辑
只是为了它,这是纯粹的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
Run Code Online (Sandbox Code Playgroud)
所述"${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
Run Code Online (Sandbox Code Playgroud)
不幸的是,Bash不允许printf -v
(类似于sprintf()
)对数组元素进行赋值,因此printf -v "line[6]" ...
不起作用.
编辑:从Bash 4.1开始,printf -v
现在可以对数组元素进行赋值.例:
printf -v 'line[6]' '%d' "0x${line[3]:10:4}"
Run Code Online (Sandbox Code Playgroud)
需要数组引用周围的引号以防止可能的文件名匹配.如果当前目录中存在名为"line6"的文件并且未引用引用,则将line6
创建(或更新)包含printf输出的名为的变量.关于文件的其他任何内容,例如其内容,都将起作用.只有名字 - 只有切线.
这似乎有效:
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;
}'
Run Code Online (Sandbox Code Playgroud)
对于您的样本输入数据,它会产生:
123711184642,02,3583090366663629,639f02,292,14292
123715942138,01,3538710295145500,639f02,45014,50755
123711616258,02,3548370476972758,639f02,72,22322
Run Code Online (Sandbox Code Playgroud)
字符串连接'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;
}'
Run Code Online (Sandbox Code Playgroud)
以0x前缀字符串被迫整数呈现给时printf()
和%d
格式.
上面的代码与awk
MacOS X 10.6.5(版本20070501)上的本机代码完美搭配; 遗憾的是,它不适用于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);
}'
Run Code Online (Sandbox Code Playgroud)
这个答案专注于展示如何通过awk进行转换.
--non-decimal-data
根据GNU Awk用户指南,不建议使用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) }
Run Code Online (Sandbox Code Playgroud)
你可以用它
awk '{cmd="printf %d 0x" $1; cmd | getline decimal; close(cmd); print decimal}'
Run Code Online (Sandbox Code Playgroud)
但它相对较慢.如果您要转换许多以换行符分隔的十六进制数字,则以下内容更快:
awk 'BEGIN{cmd="printf \"%d\n\""}{cmd=cmd " 0x" $1}END{while ((cmd | getline dec) > 0) { print dec }; close(cmd)}'
Run Code Online (Sandbox Code Playgroud)
如果为单个printf命令添加了很多参数,则可能会出现问题.
根据我的经验,以下适用于Linux:
awk -Wposix '{printf("%d\n","0x" $1)}'
Run Code Online (Sandbox Code Playgroud)
我在Ubuntu Linux 14.04中通过gawk,mawk和original-awk测试了它.通过original-awk,该命令显示一条警告消息,但您可以通过2>/dev/null
shell中的重定向指令将其隐藏.如果您不想这样做,您可以删除-Wposix
原始awk的情况,如下所示:
awk $(awk -Wversion >/dev/null 2>&1 && printf -- "-Wposix") '{printf("%d\n","0x" $1)}'
Run Code Online (Sandbox Code Playgroud)
(在bash 4,你可以替换>/dev/null 2>&1
的&>/dev/null
)
注意:-Wposix技巧可能不适用于OS X和某些BSD OS变体中使用的nawk.