如何使用十六进制数字对CSV文件进行排序?

nzrxty8p  于 2022-12-06  发布在  其他
关注(0)|答案(2)|浏览(244)

我有一个金发碧眼的时刻,似乎不能让我的头周围,但我有一个csv文件(如下所示),我想排序的第一行的值-六个数字(从小到大)

570e2e5c,1460539517,SOM3-String-123,08-5a-0c-59
570e2e81,1460539520,SOM3-String-123,08-00-0c-59
570e2e87,1460539521,SOM3-String-123,09-5e-6b-22
570e2e5e,1460539518,SOM3-String-123,08-00-0c-59
570e2e90,1460539522,SOM3-String-123,08-00-0c-59
570e2e95,1460539523,SOM3-String-123,09-00-67-22
570e2e60,1460539519,SOM3-String-123,09-00-68-22

**问:**如何用BASH脚本按行的第一个元素(十六进制)来整理csv文件的行?
附录:

因此,我用以下代码将十六进制字符串转换为十进制字符串:

IFS=','
while read f1 f2 f3 f4 
do 

f1_upper_case=`echo "$f1" | tr '[:lower:]' '[:upper:]'`
f1_dec=$((16#$f1_upper_case))
echo "$f1_dec,$f2,$f3,$f4" >>$csv_temp 

done < $csv

我将尝试在csv文件中按$f1_dec排序。

qvtsj1bj

qvtsj1bj1#

如果字符串的位数和字母大小写都相同,就像示例数据中的情况一样,则可以按原样排序。默认的词法排序会将它们按正确的顺序排序,因为十六进制数字0-9a-f在标准字符集中是按该顺序出现的。
如果你有一些数字有不同的位数,或者你在字母数字上混合了大小写,那么你最好的选择可能是转换成十进制,按数字排序,然后再转换回来。如果你有GNU版本的awk,你可以用它来做转换:

awk -v{,O}FS=, '{$1=strtonum("0x"$1)}1' $filename | 
    sort -t, -n -k1,1 |
    awk -v{,O}FS=, '{$1=sprintf("%x",$1)}1' >$new_filename

在示例输入上运行,我得到以下输出:

570e2e5c,1460539517,SOM3-String-123,08-5a-0c-59
570e2e5e,1460539518,SOM3-String-123,08-00-0c-59
570e2e60,1460539519,SOM3-String-123,09-00-68-22
570e2e81,1460539520,SOM3-String-123,08-00-0c-59
570e2e87,1460539521,SOM3-String-123,09-5e-6b-22
570e2e90,1460539522,SOM3-String-123,08-00-0c-59
570e2e95,1460539523,SOM3-String-123,09-00-67-22

说明:
-v name=value告诉awk设置将存在于程序上下文中的变量;这是一种方便的方法来注入值,而不必处理复杂的引用,因为字符串插入到代码中。2但是有些变量名是特殊的; FS告诉awk使用什么(F)字段(S)分隔符将输入行拆分成字段,OFS告诉它在打印行时使用什么(O)输出字段分隔符。-v{,O}FS=,序列只是将两个变量设置为相同值的快捷方式;它通过shell的大括号扩展扩展为-vFS=, -vOFS=,。因此,在awk程序中,每一行都将被预先用逗号拆分为字段,各个字段的值位于变量$1$2中,依此类推。当这些变量被更改时,它们将在打印出来时用逗号重新连接在一起。
-v选项之后传递给awk的字符串中的代码是要运行的awk程序。针对每行输入检查每个条件,然后如果条件为真,则对该块进行评估。如果出现的块没有条件,则在每行上运行该块;如果出现一个条件而没有块,它将导致打印出当前行--或者如果其它块已经进行了修改,则打印出由OFS连接的当前行的字段。
上面的程序使用两个默认值;每个都以没有条件的程式码区块开始,因此会在每一行执行,并以没有程式码区块的条件结束:1,它始终为true,因此在代码块进行更改后,每一行都将打印出来。
第一个awk程序使用strtonum函数将第一个字段转换为十进制。BSD awk(也是macOS自带的)没有strtonum,我们必须在字段值前面加上“0x”,这样strtonum就知道把它当作十六进制,但是一旦它是一个数值,它就会被打印成十进制。所以awk的输出和输入是一样的,除了第一个字段被转换成十进制。
我们将其输入sort,让它按第一个(-k1,1)逗号分隔(-t,)字段进行数字排序(-n),然后将排序后的输出输入第二个awk,它使用sprintf函数将第一个数字字段转换回十六进制。

ej83mcc0

ej83mcc02#

输入:

$ cat /tmp/so36636125.txt 
570e2e5c,1460539517,SOM3-String-123,08-5a-0c-59
570e2e81,1460539520,SOM3-String-123,08-00-0c-59
570e2e87,1460539521,SOM3-String-123,09-5e-6b-22
570e2e5e,1460539518,SOM3-String-123,08-00-0c-59
570e2e90,1460539522,SOM3-String-123,08-00-0c-59
570e2e95,1460539523,SOM3-String-123,09-00-67-22
570e2e60,1460539519,SOM3-String-123,09-00-68-22

转型一号班轮:

$ awk '{ dec = sprintf("%d", "0x" $1); print dec " "  $0 }' /tmp/so36636125.txt | sort -n -k 1 | cut -f2- -d' '
570e2e5c,1460539517,SOM3-String-123,08-5a-0c-59
570e2e5e,1460539518,SOM3-String-123,08-00-0c-59
570e2e60,1460539519,SOM3-String-123,09-00-68-22
570e2e81,1460539520,SOM3-String-123,08-00-0c-59
570e2e87,1460539521,SOM3-String-123,09-5e-6b-22
570e2e90,1460539522,SOM3-String-123,08-00-0c-59
570e2e95,1460539523,SOM3-String-123,09-00-67-22

$ awk --version
GNU Awk 3.1.7

说明:

  • awk添加新的第一列作为十六进制数的十进制表示
  • sort在第一列上以数字表示
  • cut删除第一列

相关问题