Shell脚本实现乱序排列文件内容的多种方法(洗牌问题)

2019-09-23 09:29:23刘景俊

    即为所构造的随机函数。
    从而有:

awk 'BEGIN{srand()}{b[rand()NR]=$0}END{for(x in b)print b[x]}' data

    其实大家担心的使用内存过大的问题不必太在意,可以做一个测试:

测试环境:

PM 1.4GHz CPU,40G硬盘,内存256M的LAPTOP
SUSE 9.3  GNU bash version 3.00.16 GNU Awk 3.1.4

产生一个五十几万行的随机文件,大约有38M:

od /dev/urandom |dd  count=75000 >data

拿效率较低的方法一来说:

洗牌一次所用时间:

time awk -v N=`sed -n '$=' data` '
BEGIN{
FS="n";
RS=""
}
{
srand();
while(t!=N){
  x=int(N*rand()+1);
  a[x]++;
  if(a[x]==1)
    {
        print $x;t++
    }
  }
}
' data

结果(文件内容省略):

real    3m41.864s
user    0m34.224s
sys     0m2.102s

所以效率还是勉强可以接受的。

方法二的测试:

time awk -f awkfile datafile

结果(文件内容省略):

real    2m26.487s
user    0m7.044s
sys     0m1.371s

效率明显好于第一个。

接着考察一下方法三的效率:

time awk 'BEGIN{srand()}{b[rand()NR]=$0}END{for(x in b)print b[x]}' data

结果(文件内容省略):

real    0m49.195s
user    0m5.318s
sys     0m1.301s

对于一个38M的文件来说已经相当不错了。
--------------------------------------------------------------------

附带存一个来自 flyfly 写的 python 版本乱序代码:

#coding:gb2312
import sys
import random

def usage():
print "usage:program srcfilename dstfilename"
global filename
filename = ""
try:
filename = sys.argv[1]
except:
usage()
raise()
#open the phonebook file

f = open(filename, 'r')
phonebook = f.readlines()
print phonebook
f.close()

#write to file randomly
try:
filename = sys.argv[2]
except:
usage()
raise()

f = open(filename, 'w')
random.shuffle(phonebook)
f.writelines(phonebook)
f.close()