如何在Unix命令行或shell脚本中混洗文本文件的行?

Rug*_*man 275 random shell awk command-line shuffle

我想随机地随机播放文本文件的行并创建一个新文件.该文件可能有几千行.

我怎样才能做到这一点与cat,awk,cut等?

Joe*_*oey 349

你可以用shuf.至少在某些系统上(似乎不在POSIX中).

正如jleedev所指出的那样:sort -R也许是一种选择.至少在一些系统上; 好吧,你得到了照片.有人指出,sort -R它并不是真正的混乱,而是根据它们的哈希值对项目进行排序.

[编者注:sort -R 几乎是随机播放,除了重复的行/排序键总是彼此相邻.换句话说:只有使用独特的输入行/键才是真正的随机播放.虽然输出顺序确实是由哈希值决定的,但随机性来自于选择随机哈希函数 - 参见手册.

  • 对于OS X用户:`brew install coreutils`,然后使用`gshuf ...`(: (144认同)
  • `shuf`和`sort -R`略有不同,因为`sort -R`根据它们的**hash**随机排序元素,`sort -R`将把重复的元素放在一起,而`shuf `随机洗牌所有元素. (29认同)
  • 这是不正确的."sort -R"每次调用时都使用*不同的*随机散列键,因此每次都会产生不同的输出. (15认同)
  • `sort -R`和`shuf`应该被视为完全不同.`sort -R`是确定性的.如果您在同一输入的不同时间拨打两次,您将得到相同的答案.另一方面,`shuf`产生随机输出,因此很可能在同一输入上给出不同的输出. (14认同)
  • GNU coreutils既有`shuf`又有`sort -R`,这很奇怪. (2认同)
  • +1'shuf` - 它在我的情况下,运行速度快多(60GB洗牌了文件也许20分钟,`shuf`与`排序-R`跑向1.5+小时之前,我杀了它) (2认同)
  • 关于随机性的注意事项:根据GNU文档,"默认情况下,这些命令使用由少量熵初始化的内部伪随机生成器,但可以指向使用带有--random-source = file选项的外部源." (2认同)
  • 我假设`sort -R`比`shuf`慢,因为sort是一个'O(n logn)`操作,shuffeling是`O(n)`? (2认同)

小智 83

Perl one-liner将是Maxim解决方案的简单版本

perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile
Run Code Online (Sandbox Code Playgroud)

  • 我把这个混淆在OS X上随机播放.谢谢! (5认同)

mkl*_*nt0 60

这个答案通过以下方式补充了许多现有的答案:

  • 现有答案打包成灵活的shell函数:

    • 这些函数不仅包括stdin输入,还包括文件名参数
    • 这些函数采用额外的步骤以SIGPIPE通常的方式处理(使用退出代码安静终止141),而不是吵闹.将功能输出管道连接到提前关闭的管道(例如管道连接时)时,这一点很重要head.
  • 进行性能比较.


shuf() { awk 'BEGIN {srand(); OFMT="%.17f"} {print rand(), $0}' "$@" |
               sort -k1,1n | cut -d ' ' -f2-; }
Run Code Online (Sandbox Code Playgroud)
shuf() { perl -MList::Util=shuffle -e 'print shuffle(<>);' "$@"; }
Run Code Online (Sandbox Code Playgroud)
shuf() { python -c '
import sys, random, fileinput; from signal import signal, SIGPIPE, SIG_DFL;    
signal(SIGPIPE, SIG_DFL); lines=[line for line in fileinput.input()];   
random.shuffle(lines); sys.stdout.write("".join(lines))
' "$@"; }
Run Code Online (Sandbox Code Playgroud)
shuf() { ruby -e 'Signal.trap("SIGPIPE", "SYSTEM_DEFAULT");
                     puts ARGF.readlines.shuffle' "$@"; }
Run Code Online (Sandbox Code Playgroud)

表现比较:

注意:这些数字是在2012年末推出的带有3.2 GHz Intel Core i5的iMac和运行OSX 10.10.3的Fusion Drive上获得的.虽然时序会随着操作系统的使用而变化,机器规格,awk使用的实现(例如,awkOSX上使用的BSD 版本通常比GNU慢awk,尤其是mawk),这应该提供相对性能的一般意义.

输入文件是一个1百万行文件与产生seq -f 'line %.0f' 1000000.
时间按升序列出(最快速率):

  • shuf
    • 0.090s
  • Ruby 2.0.0
    • 0.289s
  • Perl 5.18.2
    • 0.589s
  • 蟒蛇
    • 1.342s用Python 2.7.6; 2.407s(!)使用Python 3.4.2
  • awk+ sort+cut
    • 3.003s与BSD awk; 2.388s与GNU awk(4.1.1); 1.811smawk(1.3.4);

为进一步比较,未按上述功能打包的解决方案:

  • sort -R (如果有重复的输入行,则不是真正的随机播放)
    • 10.661s - 分配更多内存似乎没有什么区别
  • 斯卡拉
    • 24.229s
  • bash 循环+ sort
    • 32.593s

结论:

  • shuf如果可以的话,使用 - 它是迄今为止最快的.
  • Ruby做得很好,其次是Perl.
  • Python明显比Ruby和Perl慢,而且,与Python版本相比,2.7.6比3.4.1快得多
  • 使用符合POSIX标准的awk+ sort+ cut组合作为最后的手段 ; awk您使用哪种实现很重要(mawk比GNU快awk,BSD awk最慢).
  • 远离sort -R,bash循环和Scala.


Nic*_*oic 27

我使用一个小的perl脚本,我称之为"unsort":

#!/usr/bin/perl
use List::Util 'shuffle';
@list = <STDIN>;
print shuffle(@list);
Run Code Online (Sandbox Code Playgroud)

我还有一个NULL分隔的版本,称为"unsort0"...用于查找-print0等等.

PS:也投了'shuf',我不知道这些天在coreutils中有什么......如果你的系统没有'shuf',上面的内容可能仍然有用.


Rug*_*man 20

这是第一次尝试在编码器上很容易但在CPU上很难为每行添加一个随机数,对它们进行排序然后从每一行中删除随机数.实际上,这些行是随机排序的:

cat myfile | awk 'BEGIN{srand();}{print rand()"\t"$0}' | sort -k1 -n | cut -f2- > myfile.shuffled
Run Code Online (Sandbox Code Playgroud)

  • UUOC.将文件传递给awk本身. (8认同)
  • shuf(){awk'BEGIN {srand()} {print rand()"\ t"$ 0}'"$ @"| 排序| cut -f2-;} (2认同)

gho*_*g74 16

这是一个awk脚本

awk 'BEGIN{srand() }
{ lines[++d]=$0 }
END{
    while (1){
    if (e==d) {break}
        RANDOM = int(1 + rand() * d)
        if ( RANDOM in lines  ){
            print lines[RANDOM]
            delete lines[RANDOM]
            ++e
        }
    }
}' file
Run Code Online (Sandbox Code Playgroud)

产量

$ cat file
1
2
3
4
5
6
7
8
9
10

$ ./shell.sh
7
5
10
9
6
8
2
1
3
4
Run Code Online (Sandbox Code Playgroud)


sca*_*cai 11

python的单线程:

python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile
Run Code Online (Sandbox Code Playgroud)

并且只打印一条随机线:

python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile
Run Code Online (Sandbox Code Playgroud)

但是请看这篇文章,了解python的缺点random.shuffle().它不适用于许多(超过2080个)元素.

  • "缺点"并非特定于Python.有限的PRNG周期可以通过从系统熵重新接种PRNG来解决,就像`/ dev/urandom`那样.从Python中使用它:`random.SystemRandom().shuffle(L)`. (2认同)

Mic*_*jer 9

简单的基于awk的功能将完成这项工作:

shuffle() { 
    awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}' | sort -n | cut -c8-
}
Run Code Online (Sandbox Code Playgroud)

用法:

any_command | shuffle
Run Code Online (Sandbox Code Playgroud)

这几乎适用于任何UNIX.在Linux,Solaris和HP-UX上测试过.

更新:

请注意,前导零(%06d)和rand()乘法使其在sort不理解数字的系统上也能正常工作.它可以通过词典顺序排序(也就是正常的字符串比较).


hof*_*anc 7

Ruby FTW:

ls | ruby -e 'puts STDIN.readlines.shuffle'
Run Code Online (Sandbox Code Playgroud)


dfr*_*kow 6

根据scai的答案,Python的一个衬里,但a)采用stdin,b)使结果可重复使用种子,c)只挑选出所有行中的200个.

$ cat file | python -c "import random, sys; 
  random.seed(100); print ''.join(random.sample(sys.stdin.readlines(), 200))," \
  > 200lines.txt
Run Code Online (Sandbox Code Playgroud)


kma*_*o23 6

一种简单直观的方法是使用shuf

例:

假设words.txt为:

the
an
linux
ubuntu
life
good
breeze
Run Code Online (Sandbox Code Playgroud)

要随机排列,请执行以下操作:

$ shuf words.txt
Run Code Online (Sandbox Code Playgroud)

这将乱码的线投向标准输出 ; 因此,您必须将其通过管道传输到类似以下的输出文件

$ shuf words.txt > shuffled_words.txt
Run Code Online (Sandbox Code Playgroud)

一种这样的随机运行可以产生:

breeze
the
linux
an
ubuntu
good
life
Run Code Online (Sandbox Code Playgroud)


nav*_*aid 5

我们有一个包来完成这项工作:

sudo apt-get install randomize-lines
Run Code Online (Sandbox Code Playgroud)

例子:

创建一个有序的数字列表,并将其保存到 1000.txt:

seq 1000 > 1000.txt
Run Code Online (Sandbox Code Playgroud)

洗牌,只需使用

rl 1000.txt
Run Code Online (Sandbox Code Playgroud)