我正在尝试在 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)
Run Code Online (Sandbox Code Playgroud)
我想按小时、分钟和秒对以上内容进行排序,如下所示:
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)
Run Code Online (Sandbox Code Playgroud)
我尝试了一些排序命令,但很难得到我想要的。如何才能做到这一点?
假设时间戳和持续时间之间的文本始终有 3 个空格分隔的单词(如示例中所示),您可以执行以下操作:
<your-file LC_ALL=C sort -nb -k6.2,6 -k8,8 -k10,10
Run Code Online (Sandbox Code Playgroud)
默认分隔符是非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-
Run Code Online (Sandbox Code Playgroud)
或者使用perl最好的extraction 和report 工具,并且具有sort内置的运算符。兰德尔·L·施瓦茨 (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}'
Run Code Online (Sandbox Code Playgroud)
或者使用@terdon 的方法,首先对具有相同持续时间的行进行重复数据删除,在排序过程中节省一些比较,但代价是操作哈希表,这可能最终在效率方面产生反作用,并最终失去排序稳定性。