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

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

ChinaUnix 确实是 Shell 高手云集的地方,只要你想得到的问题,到那里基本上都能找到答案。r2007 给出了一个取巧的方法,利用 Shell 的 $RANDOM 变量给原文件的每一行加上随机的行号然后根据这个随机行号进行排序,再把临时加上去的行号给过滤掉,这样操作之后得到的新文件就相当于被随机“洗”了一次:

复制代码 代码如下:

while read i;do echo "$i $RANDOM";done<file|sort -k2n|cut -d" " -f1

当然如果你的源文件每行的内容比较复杂的话就必须对这段代码进行改写,但只要知道了处理的关键技巧,剩下的问题都不难解决。

另外一篇来自苏蓉蓉的用 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

方法二:变换

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

复制代码 代码如下:

#! /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;
  }

}

方法三:散列

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

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

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

复制代码 代码如下:

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()

时间: 2024-09-03 18:49:25

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

linux下用shell脚本启动可执行.jar文件并关闭的方法

话不多说,开始上代码,为了偷懒,代码只是截图了,感兴趣的朋友可以看了之后自己写,这样加深印象. 上面是小弟写的shell脚本.写的不好请见谅. 首先遇到的第一个坑 我在window下写的 然后道linux中执行,在linux死活都说俺的19行有错误,俺就不明白了,哪里有错,问了下别人,也说没错.突然有个高人问我在哪编写的,小弟回答在win下,他告诉俺执行下这个命令: dos2unix server.sh 然后小弟就执行了,说命令不存在,小弟只好安装这个,执行了以下命令 yum install d

一天一个shell命令 linux文件内容操作系列-cat命令详解_linux shell

注:在awk命令之后,没有太多复杂命令,都是一些基础命令. 说明: cat,是单词 concatenate 的缩写, 把文件的内容输出到stdout.当与重定向操作符 (> 或 >>结合使用时, 一般都是用来将多个文件连接起来. 用法: 1. $cat file1 file2 file3 2. 不仅可以从文件中读取内容并且拼接,还能从标准输入流中读取 例如:$echo 'some content' |  cat - file.txt 解释:这里的 - 就代表了 'some content

shell脚本操作oracle删除表空间、创建表空间、删除用户_linux shell

oracle下表空间的导出,用户的删除,表空间删除,用户新建,表空间新建,数据导入的shell使用非oracle用户执行该脚本参数说名$1:base表空间的用户名$2:同步表空间的用户名使用场景测试用,base表空间用于升级建立一些固化数据.同步表空间用于测试用,每次去和base表空间拉平数据 复制代码 代码如下: #!/bin/shoraclehome=$ORACLE_HOMEecho $oraclehomelocaldir="/oracle/data"echo $localdir#

Shell脚本实现监控swap空间使用情况和查看占用swap的进程_linux shell

复制代码 代码如下: #!/bin/bash   echo -e `date +%y%m%d%H%M` echo -e "PID\t\tSwap\t\tProc_Name"   # 拿出/proc目录下所有以数字为名的目录(进程名是数字才是进程,其他如sys,net等存放的是其他信息) for pid in `ls -l /proc | grep ^d | awk '{ print $9 }'| grep -v [^0-9]` do     # 让进程释放swap的方法只有一个:就是重

Shell脚本实现检查服务器安全状态(用户、登录IP、防火墙检查)_linux shell

说明:大家平时对Linux服务器安全主要是对系统用户的检查,登陆服务器IP检查,以及防火墙状态检查! 1.需要把正确系统用户名存储在/root/liu_shell/local_user.txt文件中,然后进行比较! 2.对登陆IP判断是不是以192.168.1和192.168.2开头的IP为正常IP! 3.判断iptables状态! 复制代码 代码如下:   #!/usr/bin/python #coding=utf-8 import sys,os,re,socket host=str(sock

在一个文件中有10G个整数,乱序排列,要求找出中位数

 题目:在一个文件中有 10G 个整数,乱序排列,要求找出中位数.内存限制为 2G.只写出思路即可(内存限制为 2G的意思就是,可以使用2G的空间来运行程序,而不考虑这台机器上的其他软件的占用内存). 关于中位数:数据排序后,位置在最中间的数值.即将数据分成两部分,一部分大于该数值,一部分小于该数值.中位数的位置:当样本数为奇数时,中位数=(N+1)/2 ; 当样本数为偶数时,中位数为N/2与1+N/2的均值(那么10G个数的中位数,就第5G大的数与第5G+1大的数的均值了). 分析:明显是一道

Shell脚本切割tomcat的日志文件_linux shell

鉴于在调试logback和log4j的文件切割一直无法成功,随性用shell写个脚本用来切割tomcat下的日志文件(大家如果有在logback或log4j使用文件切割成功的话,可以留下使用方式,先谢谢了) 1:废话少说,直接贴上脚本: #!/bin/sh log_dir=/var/log/tomcat monitor_file=$1 #tomcat目录下的catalina.out文件的绝对路径 file_size=`du $monitor_file | awk '{print $1}'` if

Shell脚本实现复制文件到多台服务器的代码分享_linux shell

在多机集群环境中,经常面临修改配置文件后拷贝到多台服务器的情况,传统的执行scp比较麻烦,所以写了以下shell脚本,可以将指定文件拷贝到多台机器. 使用方法请参见HELP部分代码. #!/bin/bash help() { cat << HELP --------------HELP------------------------ This shell script can copy file to many computers. Useage: copytoall filename(ful

安卓-实现一个gridview有9个图片.要乱序排列.怎么为图片设置标志?.乱序后知道是原来是哪个位置?

问题描述 实现一个gridview有9个图片.要乱序排列.怎么为图片设置标志?.乱序后知道是原来是哪个位置? 实现一个gridview有9个图片.要乱序排列.怎么为图片设置标志?.乱序后知道是原来是哪个位置. gridview每一次初始化都要不同的位置排列(乱序排列).排好后要知道原来的位置.怎么设置.小白求教 O(∩_∩)O谢谢 解决方案 程序里用一个数组,记录原始位置就可以了 解决方案二: 不知道要怎么实现可以具体点吗?怎么乱序处理?.谢谢 可以留个联系方式吗?qq什么的. 解决方案三: 在