我正在尝试在 AIX 系统上按正确的顺序按 3 个不同的列进行排序。
下面是一个较大文件的摘录,显示了开括号之间的最长运行时间,例如(0 小时 0 分钟 1.030 秒)。请记住,第一列不会按顺序排列,因为文件的输出是并行运行的。下面是我从 2500 行中提取的 10 个运行时间最长的进程。现在我想对运行时间最长的前十个进程从最短时间到最长时间进行排序:
2023-01-04 12:32:08: Table seqhi completed (0 hrs 0 mins 1.020 Secs)
2023-01-04 12:32:09: Table iinvd completed (0 hrs 0 mins 1.028 Secs)
2023-01-04 12:32:10: Table iaudl completed (0 hrs 0 mins 1.030 Secs)
2023-01-04 12:32:11: Table ccdd_save completed (1 hrs 0 mins 1.021 Secs)
2023-01-04 12:32:13: Table upi_brordrep_tmp_aj completed (0 hrs 0 mins 1.028 Secs)
2023-01-04 12:32:07: Table srdel completed (0 hrs 2 mins 1.592 Secs)
2023-01-04 12:32:09: Table iibt completed (0 hrs 0 mins 1.020 Secs)
2023-01-04 12:32:10: Table atprdd completed (0 hrs 0 mins 1.018 Secs)
2023-01-04 12:33:43: Table atseld completed (0 hrs 1 mins 33.868 Secs)
2023-01-04 12:32:10: Table abc_irctd completed (0 hrs 0 mins 1.029 Secs)
我想按小时、分钟和秒对以上内容进行排序,如下所示:
2023-01-04 12:32:10: Table atprdd completed (0 hrs 0 mins 1.018 Secs)
2023-01-04 12:32:08: Table seqhi completed (0 hrs 0 mins 1.020 Secs)
2023-01-04 12:32:09: Table iibt completed (0 hrs 0 mins 1.020 Secs)
2023-01-04 12:32:09: Table iinvd completed (0 hrs 0 mins 1.028 Secs)
2023-01-04 12:32:13: Table upi_brordrep_tmp_aj completed (0 hrs 0 mins 1.028 Secs)
2023-01-04 12:32:10: Table abc_irctd completed (0 hrs 0 mins 1.029 Secs)
2023-01-04 12:32:10: Table iaudl completed (0 hrs 0 mins 1.030 Secs)
2023-01-04 12:33:43: Table atseld completed (0 hrs 1 mins 33.868 Secs)
2023-01-04 12:32:07: Table srdel completed (0 hrs 2 mins 1.592 Secs)
2023-01-04 12:32:11: Table ccdd_save completed (1 hrs 0 mins 1.021 Secs)
我尝试了一些排序命令,但很难得到我想要的。如何才能做到这一点?
答案1
假设时间戳和持续时间之间的文本始终有 3 个空格分隔的单词(如示例中所示),您可以执行以下操作:
<your-file LC_ALL=C sort -nb -k6.2,6 -k8,8 -k10,10
默认分隔符sort
是非空白和空白之间的过渡,因此没有的排序键-b
将包含前导空白。通过使用-b
来剥离这些,我们确保指定为从第六个字段的第二个字符开始的第一个键就在(
.
所有键均以n
数字方式解释。使用LC_ALL=C
,我们确保小数基数字符应该.
与用户的区域设置无关。
请注意,它假设秒和分钟部分不超过 60。例如,即使后者更长,它也会排(0 hrs 1 mins 10.1 Secs)
在后面。(0 hrs 0 mins 120.592 Secs)
通过管道tail
获得前十名。
如果排序键不能是具有固定偏移量的字段或字段的一部分,常见的方法是使用其他工具提取键,将它们复制到行的开头,然后排序并删除它们在一个装饰-排序-取消装饰时尚:
d='\([[:digit:]]\{1,\}\)'
<your-file sed -n "s/^.*($d hrs $d mins $d\.$d Secs)\$/\1:\2:\3.\4:&/p" |
LC_ALL=C sort -nt: -k1,1 -k2,2 -k3,3 |
cut -d: -f4-
或者使用perl
最好的e
xtraction 和r
eport 工具,并且具有sort
内置的运算符。兰德尔·施瓦茨 (Randal L. Schwartz) 以他的名字命名了“装饰-排序-不装饰”这一习语你通常会在那里使用:
<your-file perl -ne '
push @records, [$_, $3 + 60 * ($2 + 60 * $1)]
if /\((\d+) hrs (\d+) mins (\d+\.\d+) Secs\)$/;
END {print $_->[0] for sort {$a->[1] <=> $b->[1]} @records}'
或者使用@terdon 的方法首先对具有相同持续时间的行进行重复数据删除,在排序过程中节省一些比较,但代价是操作哈希表,这可能最终会在效率方面产生反作用,并最终失去排序稳定性。
答案2
Perl 方法:
$ perl -lne '/(\d+)\s*hrs\s*(\d+)\s*mins\s*([0-9.]+)\s*Secs/;
push @{$k{($1*60*60)+($2*60)+($3)}},$_;
}{
for $t (sort {$a <=> $b} keys(%k)){
print join "\n",@{$k{$t}}
}; ' file
2023-01-04 12:32:10: Table atprdd completed (0 hrs 0 mins 1.018 Secs)
2023-01-04 12:32:08: Table seqhi completed (0 hrs 0 mins 1.020 Secs)
2023-01-04 12:32:09: Table iibt completed (0 hrs 0 mins 1.020 Secs)
2023-01-04 12:32:09: Table iinvd completed (0 hrs 0 mins 1.028 Secs)
2023-01-04 12:32:13: Table upi_brordrep_tmp_aj completed (0 hrs 0 mins 1.028 Secs)
2023-01-04 12:32:10: Table abc_irctd completed (0 hrs 0 mins 1.029 Secs)
2023-01-04 12:32:10: Table iaudl completed (0 hrs 0 mins 1.030 Secs)
2023-01-04 12:33:43: Table atseld completed (0 hrs 1 mins 33.868 Secs)
2023-01-04 12:32:07: Table srdel completed (0 hrs 2 mins 1.592 Secs)
2023-01-04 12:32:11: Table ccdd_save completed (1 hrs 0 mins 1.021 Secs)
这没有限制史蒂芬的回答(0 hrs 1 mins 10.1 Secs)
,并且会在 之前正确排序(0 hrs 0 mins 120.592 Secs)
。另一方面,这似乎是一个不太可能出现的问题,而且 Stéphane 的方法既简单又快速,因此除非您知道有超过 60 秒的案例,否则我会改用该方法。
答案3
我熟悉的“sort”命令按字母顺序而不是数字顺序排序(10,11,12 在 6,7,8 之前排序),因此您可能需要在 -k 字符串后面添加“g”(例如“- k8,8g”而不是“-k8,8”)来按数字顺序对事物进行排序。
答案4
警告:当前答案的第一行是 (GNU)sort 命令,该命令不适用于普通 AIX 系统。 (有时,gnu-sort 也以 gsort 的名称安装)
sort -k6Vb example
在哪里:
-k6
用于从字段 6 到末尾进行排序Vb
版本排序(遵循人类直觉的排序)是否忽略前导空格
(\感谢{杰夫和史蒂芬})