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