• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >linux shell > Shell脚本实现乱序排列文件内容的多种方法(洗牌问题)

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

作者:junjie 字体:[增加 减小] 来源:互联网

junjie 通过本文主要向大家介绍了shell脚本,shell脚本编程,shell脚本学习指南,shell脚本实例,linux shell脚本等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

洗牌问题:洗一副扑克,有什么好办法?既能洗得均匀,又能洗得快?即相对于一个文件来说怎样高效率的实现乱序排列?

ChinaUnix 确实是 Shell 高手云集的地方,只要你想得到的问题,到那里基本上都能找到答案。r2007 给出了一个取巧的方法,利用 Shell 的 $RANDOM 变量给原文件的每一行加上随机的行号然后根据这个随机行号进行排序,再把临时加上去的行号给过滤掉,这样操作之后得到的新文件就相当于被随机“洗”了一次:
while read i;do echo "$i $RANDOM";done<file|sort -k2n|cut -d" " -f1
</div>
当然如果你的源文件每行的内容比较复杂的话就必须对这段代码进行改写,但只要知道了处理的关键技巧,剩下的问题都不难解决。

另外一篇来自苏蓉蓉的用 awk 来实现洗牌效果的随机文件排序代码分析(原贴在这里,以及对此帖的一个后续讨论,如果你没有登录帐号的话可以到这里查看精华区文章)则写的更为详细:
--------------------------------------------------------------------
关于洗牌问题,其实已经有了一个很好的shell解法,这里另外给三个基于AWK的方法,有错误之处还请不吝指出。

方法一:穷举

类似于穷举法,构造一个散列来记录已经打印行出现行的次数,如果出现次数多于一次则不进行处理,这样可以防止重复,但缺点是加大了系统的开销。
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
</div>
方法二:变换

基于数组下标变换的办法,即用数组储存每行的内容,通过数组下标的变换交换数组的内容,效率好于方法一。
#! /usr/awk

BEGIN{
srand();
}

{
b[NR]=$0;
}

END{

C(b,NR);
for(x in b)
  {
    print b[x];
  }}

function C(arr,len,i,j,t,x){

for(x in arr)
  {
      i=int(len*rand())+1;
      j=int(len*rand())+1;
      t=arr[i];
      arr[i]=arr[j];
      arr[j]=t;
  }

}
</div>
方法三:散列

    三个方法中最好的。
    利用AWK中散列的特性(详细请看:info gawk 中的7.x ),只要构造一个随机不重复的散列函数即可,因为一个文件每行的linenumber是独一无二的,所以用:

    随机数+每行linenumber    ------对应------>    那一行的内容

    即为所构造的随机函数。
    从而有:
awk 'BEGIN{srand()}{b[rand()NR]=$0}END{for(x in b)print b[x]}' data
</div>

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

测试环境:

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
</div>
拿效率较低的方法一来说:

洗牌一次所用时间:
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
</div>
结果(文件内容省略):
real    3m41.864s
user    0m34.224s
sys     0m2.102s
</div>
所以效率还是勉强可以接受的。

方法二的测试:
time awk -f awkfile datafile
</div>
结果(文件内容省略):
real    2m26.487s
user    0m7.044s
sys     0m1.371s
</div>
效率明显好于第一个。

接着考察一下方法三的效率:
time awk 'BEGIN{srand()}{b[rand()NR]=$0}END{for(x in b)print b[x]}' data
</div>
结果(文件内容省略):
real    0m49.195s
user    0m5.318s
sys     0m1.301s
</div>
对于一个38M的文件来说已经相当不错了。
--------------------------------------------------------------------

附带存一个来自 flyfly 写的 python 版本乱序代码:
#coding:gb2312
import sys
import random

def usage():
print "usage

您可能想查找下面的文章:

  • Shell脚本监控目录内文件改动
  • 实现自动清除日期目录shell脚本实例代码
  • 使用Linux shell脚本实现FTP定时执行批量下载指定文件
  • shell脚本连接并重启远程服务器的方法
  • shell 脚本安装PHP扩展的简单方法
  • Linux shell脚本输出日志笔记整理(必看篇)
  • shell脚本实现分日志级别输出的方法
  • shell将脚本输出结果记录到日志文件的实现
  • 输出执行操作和打印日志的shell脚本实例
  • shell脚本 自动创建用户详解及实例代码

相关文章

  • Shell 命令替换的两种方式
  • sed初学者实用说明
  • 浅析Linux系统下安装wetty和使用说明
  • linux下通过命令行获取gmail的新邮件
  • 8个实用的Shell脚本分享
  • 详解Linux命令中的正则表达式
  • 自动重启服务的shell脚本代码
  • Shell脚本实现IP地址合法性判断
  • Shell中获取脚本所在目录绝对路径的方法
  • 利用shell获取指定日期前N天的日期

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • Bash Shell 注释多行的几种方法
    • Linux复制文件命令cp之使用解说
    • Linux命令行里的“瑞士军刀”
    • Git中需要熟记的命令小结
    • Shell脚本if else语句小结
    • linux shell查看当前外网IP
    • 利用linux的timerfd_create实现计时器示例分享
    • shell脚本监控mysql主从状态
    • 简单的远程FTP定时备份Shell脚本分享
    • Linux shell脚本全面学习入门

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有