8

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

$ 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) 进行排序,但是在该值内,我如何对最后一个字段(由 分隔/)进行排序?

4

4 回答 4

13

该数据集最简单的技巧是将第二列视为版本号。

$ 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
于 2013-12-20T09:57:29.143 回答
5

只要'|'文本中没有其他字符,以下代码就对我有用。

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

于 2014-09-15T13:35:05.777 回答
5

一个小技巧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的所有分隔-F'[|/]'符先打印排序键$2"\t"$4,然后打印输入行$0
  • 然后sort用多个键做一个-k1 -k2(注意:不一样-k1,2
  • 然后cut回到输入行

多场景通用

于 2017-10-12T09:21:24.883 回答
2

您可以使用这个(低效但简单)的脚本:

#!/usr/bin/perl
print sort  {   @ka = split ?[|/]?, $a;
                @kb = split ?[|/]?, $b;
                $ka[1] <=> $kb[1]
             || $ka[3] <=> $kb[3]
             || $ka[0] cmp $kb[0]
            } <>

|| $ka[0] cmp $kb[0]如果您不关心按文本消息排序的具有相等值的行,则可以省略该行。

于 2013-06-06T09:27:31.880 回答