2016-12-17 56 views
0

给予相同的输入列表如下:如何随机排序一个关键,而另一个保持与GNU“之类的”原来的排序顺序

405:[email protected] 
405:[email protected] 
405:[email protected] 
405:[email protected] 
405:[email protected] 
405:[email protected] 
004:[email protected] 
004:[email protected] 
004:[email protected] 
101:[email protected] 
101:[email protected] 
101:[email protected] 
101:[email protected] 
101:[email protected] 
101:[email protected] 
005:[email protected] 
005:[email protected] 
005:[email protected] 

(正如你所看到的,第一场是随机(原始输入具有数字顺序的所有第一个字段,其中004先到达,然后是005,101,405等),但第二个字段按字母顺序排列在第一个字符上。)

什么是期望的是随机排序,其中第一个字段 - 由冒号“:”分隔,随机排序,以便在随机排序过程中第二个字段的所有条目都不重要,所以l因为所有第一个字段相同的行被分组在一起,但随机分布在整个文件中 - 也就是让第二个字段随机排序。也就是说,在最终的输出中,第一个字段中具有相同值的行被分组在一起(但是随机分布在整个文件中),而且第二个字段也是随机排序的。我不能得到这个理想的结果,因为我不太熟悉排序键和什么。

所需的输出将类似于此:

405:[email protected] 
405:[email protected] 
405:[email protected] 
405:[email protected] 
405:[email protected] 
405:[email protected] 
004:[email protected] 
004:[email protected] 
004:[email protected] 
101:[email protected] 
101:[email protected] 
101:[email protected] 
101:[email protected] 
101:[email protected] 
101:[email protected] 
005:[email protected] 
005:[email protected] 
005:[email protected] 

有谁知道如何实现这种类型的排序?

谢谢!

回答

2

你可以很容易地与awk做到这一点。

作为一个班轮:

awk -F: 'BEGIN{cmd="sort -R"} $1 != key {close(cmd)} {key=$1; print | cmd}' input.txt 

或者碎裂开来,便于解释:

  • -F: - 设置awk的字段分隔符冒号。
  • BEGIN{cmd="sort -R"} - 在我们开始之前,设置一个变量来执行“随机排序”。这个在FreeBSD上适用于我。还应该使用GNU排序。
  • $1 != key {close(cmd)} - 如果当前行有比上一个处理不同的第一场,关闭输出管...
  • {key=$1; print | cmd} - 最后,设置“键”变种,并打印当前行,管道输出通过存储在cmd变量中的命令。

这个用法利用了一点awk的精彩。当你通过一个字符串(不管它是否存储在一个变量中)时,该管道在使用时自动创建。您可以随时关闭它,随后的使用将重新打开一个新命令。

这个的影响是,每次你close(cmd),你打印当前集随机排序的行。一旦你到达文件末尾,awk自动关闭cmd

当然,对于这个解决方案的工作,至关重要的是所有具有共享第一个字段的行都被分组在一起。

+0

这当然做到了。能够看到在'awk'单线程中完成也是令人惊讶的;我在PHP中实现了相同的功能,但是在大约30行代码中(包括文件读取,语法检查等)涉及大量的数组遍历和混洗。这当然更快,更高效。 – Brendan

+0

尽管我的原始问题,你知道它可能与GNU'sort'吗?我不这么认为,但如果是这样,我想看看排序语法。 – Brendan

+0

我相当肯定地认为它不能单独使用GNU排序。你在你的问题中描述的那种很简单,就像按照第一个字段分组的简单随机化一样,根本不是一种排序。当涉及到它时,我们只使用GNU排序来在这里随机化。你可以用其他的东西替换那个命令 - 'tac'来颠倒每个部分的顺序,或者'mailx'发送每个组作为电子邮件的主体。 – ghoti

1

不是作为优雅,但不同的方法

$ awk -F: '!($1 in a){a[$1]=c++} {print a[$1] "\t" $0}' file | 
    sort -R -k2 | 
    sort -nk1,1 -s | 
    cut -f2- 

,或者该替代不假定初始分组

$ sort -R file | 
    awk -F: '!($1 in a){a[$1]=c++} {print a[$1] "\t" $0}' | 
    sort -nk1,1 -s | 
    cut -f2- 
相关问题