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

标签 bash sorting csv hex

我有一个金发时刻,似乎无法理解它,但我有一个 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 排序。

最佳答案

如果字符串都具有相同的数字位数和相同的字母大小写(如示例数据中所示),则您可以按原样排序。默认的词法排序会将它们按正确的顺序排列,因为十六进制数字 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 设置一个将存在于程序上下文中的变量;这是一种注入(inject)值的简便方法,无需处理伴随字符串插值到代码中的引用复杂性。但是有些变量名是特殊的; FS 告诉 awk 使用什么 (F)ield (S) 分隔符将输入行拆分为字段,而 OFS 告诉它什么 (O ) 输出字段分隔符以在打印行退出时使用。 -v{,O}FS=, 序列只是将两个变量设置为相同值的快捷方式;它通过 shell 的大括号扩展扩展为 -vFS=, -vOFS=,。因此在 awk 程序中,每一行都将用逗号预先拆分成字段,变量 $1$2 中的各个字段值等等。当这些变量发生变化时,它们将在打印出来时用逗号重新连接在一起。

-v 选项后传递给awk 的字符串中的代码是要运行的awk 程序。这样的程序是一系列(条件, block )对;针对每一行输入检查每个条件,然后如果条件为真,则评估 block 。如果一个 block 没有条件出现,它就在每一行上运行;如果一个条件在没有 block 的情况下出现,它会导致打印出当前行——或者由 OFS 加入的当前行的字段,如果其他 block 已经进行了修改的话。

上面的程序都使用了默认值;每个都以一个没有条件的代码块开始,所以它在每一行上运行,并以一个没有代码块的条件结束:1,它总是为真,所以在代码块完成后每一行都被打印出来它的变化。

第一个awk 程序使用strtonum 函数将第一个字段转换为十进制。这就是为什么这个解决方案只适用于 GNU awk; BSD awk(也是在 macOS 上发布的)没有 strtonum。我们必须在字段值前添加“0x”,以便 strtonum 知道将其视为十六进制,但一旦它是数值,它将被打印为十进制。所以 awk 的输出与输入相同,除了第一个字段转换为十进制。

我们将其提供给 sort,告诉它根据第一个 (-k1,1) 逗号对数字 (-n) 进行排序- separated (-t,) 字段,然后将排序后的输出输入到第二个 awk 中,它使用 sprintf 函数首先转换数字字段返回十六进制。

关于bash - 如何用十六进制数字对 CSV 文件进行排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36636125/

相关文章:

Javascript:排序多维数组

python - 解析 CSV 并使用多个值分隔字段

perl - 对具有无序整数列的文件进行排序

linux - ". filename"从/bin/sh 运行时找不到文件,从/bin/bash 运行;为什么?

Bash bool 表达式及其赋值

python-3.x - Pandas 将重复项删除到 CSV

c# - 如何创建由开始和停止按钮控制的 CSV 文件

bash - ts流制作中的ffmpeg两遍

sorting - 删除非常大的 .text 文件中的重复行的最快方法

arrays - 部分排序数组的最短时间?