Unix 如何使用不同的字段分隔符对多个字段进行排序

Unix 如何使用不同的字段分隔符对多个字段进行排序,unix,sorting,Unix,Sorting,我想按多字段和多字段分隔符对文件进行排序。请帮忙。这是我的示例数据文件: $ cat Data3 My Text|50002/100/43 My Message|50001/100/7 Help Text|50001/100/7 Help Message|50002/100/11 Text Message|50001/100/63 Visible Text|50001/100/52 Invisible Text|50002/100/1 第一个字段分隔符是管道符号,第二个字段分隔符是/。我想先在

我想按多字段和多字段分隔符对文件进行排序。请帮忙。这是我的示例数据文件:

$ cat Data3
My Text|50002/100/43
My Message|50001/100/7
Help Text|50001/100/7
Help Message|50002/100/11
Text Message|50001/100/63
Visible Text|50001/100/52
Invisible Text|50002/100/1
第一个字段分隔符是管道符号,第二个字段分隔符是
/
。我想先在第二个字段中对这些数据进行排序,然后在第二个字段中按照最后一个字段的顺序对这些数据进行排序(以
/
分隔)。最后,我的排序数据应该如下所示:

Help Text|50001/100/7
My Message|50001/100/7
Visible Text|50001/100/52
Text Message|50001/100/63
Invisible Text|50002/100/1
Help Message|50002/100/11
My Text|50002/100/43
通过使用
sort-k2,2n-t'|'
,我可以对字段2(
50001/50002
)进行排序,但在该值范围内,我如何对最后一个字段(由
/
分隔)进行排序?

您可以使用以下(效率低但简单)脚本:

#/usr/bin/perl
打印排序{@ka=split?[|/]?,$a;
@kb=拆分?[|/]?,$b;
$ka[1]$kb[1]
||$ka[3]$kb[3]
||$ka[0]cmp$kb[0]
} 

如果不希望按文本消息对具有相等值的行进行排序,则可以省略行
|ka[0]cmp$kb[0]

此数据集的最简单技巧是处理第二列是版本号

$ cat Data3 | sort -k2,2V -t'|'
Help Text|50001/100/7
My Message|50001/100/7
Visible Text|50001/100/52
Text Message|50001/100/63
Invisible Text|50002/100/1
Help Message|50002/100/11
My Text|50002/100/43
然而,这并不总是取决于您的输入。这将起作用,因为第二列中的值相同

您可以按照fedorqui的建议运行排序两次,第二次运行稳定排序。从手册页:-s,--stable(通过禁用最后比较来稳定排序)

根据第二排序标准进行第一次排序。然后执行稳定排序,即在共享主排序条件中相同键的行中保持排序顺序

$ cat Data3 | sort -k3,3n -t'/' | sort -k2,2n -t'|' -s
Help Text|50001/100/7
My Message|50001/100/7
Visible Text|50001/100/52
Text Message|50001/100/63
Invisible Text|50002/100/1
Help Message|50002/100/11
My Text|50002/100/43
在这种情况下,您有点幸运,因为-k2,2n-t'|'将第二列“50001/100/7”视为一个数字,它可能是50001。如果使用逗号分隔而不是斜杠,并且在您的环境中使用了不同的语言环境,则可能会出现奇怪的情况。例如,默认情况下,在我的环境中运行en_US.UTF-8,其行为如下

$ cat Data3 | tr '/' ',' | sort -k3,3n -t',' | LC_NUMERIC=en_US.UTF-8 sort -k2,2n -t'|' -s
Help Text|50001,100,7
My Message|50001,100,7
Invisible Text|50002,100,1
Visible Text|50001,100,52
Text Message|50001,100,63
Help Message|50002,100,11
My Text|50002,100,43
您所期望的是:

$ cat Data3 | tr '/' ',' | sort -k3,3n -t',' | LC_NUMERIC=C sort -k2,2n -t'|' -s
Help Text|50001,100,7
My Message|50001,100,7
Visible Text|50001,100,52
Text Message|50001,100,63
Invisible Text|50002,100,1
Help Message|50002,100,11
My Text|50002,100,43

只要文本中没有额外的
“|”
字符,下面的代码对我来说就是有效的


tr'|'''/'| sort-n-t'/'-k3-k4 | sed-re's/^([^/]*)\/(.*)$/\1 |\2/'

awk的小把戏

$ cat Data3  | awk -F'[|/]' '{print $2"\t"$4"\t"$0}' | sort -k1 -k2 -n | cut -f3-
Help Text|50001/100/7
My Message|50001/100/7
Visible Text|50001/100/52
Text Message|50001/100/63
Invisible Text|50002/100/1
Help Message|50002/100/11
My Text|50002/100/43
  • 您可以在指定了所有分隔符的情况下使用
    awk
    ,首先打印排序键
    $2”\t“$4
    ,然后打印输入行
    $0
  • 然后使用多个键执行一次排序(注意:与
    -k1,2
    不同)
  • 然后
    切回输入行

对于许多场景来说都是通用的

那么管道化结果并再次使用
排序
呢?如果效率低下,为什么要提出它?当然,因为算法、计算效率(这里的意思)并不总是主要目标。
$ cat Data3  | awk -F'[|/]' '{print $2"\t"$4"\t"$0}' | sort -k1 -k2 -n | cut -f3-
Help Text|50001/100/7
My Message|50001/100/7
Visible Text|50001/100/52
Text Message|50001/100/63
Invisible Text|50002/100/1
Help Message|50002/100/11
My Text|50002/100/43