我有一个数字列表,以逗号分隔:
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
最佳答案
以下是乔纳森答案的变体:
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如果需要的话可以选择。
编辑
只是为了好玩,这里是纯 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]”...
不起作用。
编辑:从 Bash 4.1 开始,printf -v
现在可以对数组元素进行赋值。示例:
printf -v 'line[6]' '%d' "0x${line[3]:10:4}"
需要在数组引用周围加上引号,以防止可能的文件名匹配。如果当前目录中存在名为“line6”的文件并且未引用引用,则将创建(或更新)包含 printf 输出的名为 line6
的变量。该文件的其他内容(例如其内容)不会发挥作用。只有名字——而且只是切线。
关于sed - 在 awk 或 sed 中将十六进制转换为十进制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4614775/