从bash中的文件中选择随机行

use*_*196 181 random bash shell text-processing

在bash脚本中我想从输入文件中挑出N个随机行并输出到另一个文件.如何才能做到这一点?

dog*_*ane 491

使用如下所示shuf-n选项,以获得N随机行:

shuf -n N input > output
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案.哇,shuf太快了. - 从具有40000行的文本文件中挑选10000个随机行是即时的.尝试使用'sort -R'花了这么长时间我只是CTRL-C它 (34认同)
  • @TomSmith在Mac OSX上,如果你使用的是Homebrew,你可以通过安装`coreutils`来获得shuf或GNU排序.更多信息:https://apple.stackexchange.com/questions/142860/install-shuf-on-os-x (32认同)
  • shuf很棒.我尝试了一个78亿行的文本文件,它在不到1分钟的时间内完成了这项工作. (6认同)
  • 对于mac OSX,既没有shuf也没有sort -R.有什么建议? (4认同)
  • 我在 500M 行文件上运行它以提取 1,000 行,花了 13 分钟。该文件已数月未访问,位于 Amazon EC2 SSD 驱动器上。 (4认同)
  • 如果你只是需要一组随机的线,而不是随机顺序,那么shuf效率非常低(对于大文件):更好的是进行水库采样,如[这个答案](https://stackoverflow.com/a /九十三万三千二百二十八分之六十九万二千四百○一). (2认同)
  • 它最终会多次产生同一条线吗? (2认同)

use*_*480 148

随机排序文件并选择第一100行:

$ sort -R input | head -n 100 >output
Run Code Online (Sandbox Code Playgroud)

  • `sort`实际上将相同的行排序在一起,所以如果你有重复的行并且你安装了`shuf`(一个gnu工具),那么最好将它用于此. (42认同)
  • sort -R在Mac OS X(10.9)下不可用 (28认同)
  • Andalso,如果你有一个相当庞大的文件 - 80kk行 - 这肯定会让你等待很多**,而`shuf -n`会立即行动. (22认同)
  • @tfb785:`sort -R`可能是GNU选项,安装GNU coreutils.顺便说一下,`shuf`也是coreutils的一部分. (2认同)

Ste*_*ven 23

好吧,根据对 shuf 回答的评论,他在一分钟内 shuff 了 78 000 000 000 行。

已接受的挑战...

编辑:我打破了自己的记录

powershuf 在 0.047 秒内完成

$ time ./powershuf.py -n 10 --file lines_78000000000.txt > /dev/null 
./powershuf.py -n 10 --file lines_78000000000.txt > /dev/null  0.02s user 0.01s system 80% cpu 0.047 total

Run Code Online (Sandbox Code Playgroud)

之所以如此之快,是因为我没有读取整个文件,只是将文件指针移动 10 次并在指针后打印行。

Gitlab 仓库

旧尝试

首先,我需要一个 78.000.000.000 行的文件:

$ time ./powershuf.py -n 10 --file lines_78000000000.txt > /dev/null 
./powershuf.py -n 10 --file lines_78000000000.txt > /dev/null  0.02s user 0.01s system 80% cpu 0.047 total

Run Code Online (Sandbox Code Playgroud)

这给了我一个包含780 亿个换行符的文件;-)

现在是 shuf 部分:

$ time shuf -n 10 lines_78000000000.txt










shuf -n 10 lines_78000000000.txt  2171.20s user 22.17s system 99% cpu 36:35.80 total

Run Code Online (Sandbox Code Playgroud)

瓶颈是 CPU 并且没有使用多线程,它 100% 固定 1 个核心,其他 15 个没有使用。

Python 是我经常使用的,所以我将使用它来加快速度:

seq 1 78 | xargs -n 1 -P 16 -I% seq 1 1000 | xargs -n 1 -P 16 -I% echo "" > lines_78000.txt
seq 1 1000 | xargs -n 1 -P 16 -I% cat lines_78000.txt > lines_78000000.txt
seq 1 1000 | xargs -n 1 -P 16 -I% cat lines_78000000.txt > lines_78000000000.txt
Run Code Online (Sandbox Code Playgroud)

这让我不到一分钟:

$ time ./shuf.py         










./shuf.py  42.57s user 16.19s system 98% cpu 59.752 total
Run Code Online (Sandbox Code Playgroud)

我在带有 i9 和三星 NVMe 的 Lenovo X1 Extreme 2nd gen 上进行了此操作,这为我提供了充足的读写速度。

我知道它可以变得更快,但我会留出一些空间让其他人尝试。

线计数器来源:Luther Blissett

  • 好吧,根据你对 powershuf 内部功能的描述,看起来它只是随机的。使用只有两行的文件,一行长 1 个字符,另一行长 20 个字符,我希望这两行被选择的机会相同。您的程序似乎并非如此。 (3认同)
  • 嗨斯坦因。这似乎不起作用。您是否按照我在上述评论中建议的方式对其进行了测试?在制作比 shuf 更快的东西之前,我认为您应该专注于制作像 shuf 一样准确的东西。我真的怀疑有人能用 python 程序打败 shuf。顺便说一句,除非您使用“-r”选项,否则 shuf 不会输出同一行两次,当然这需要额外的处理时间。 (2认同)
  • 问题是如何从 bash 脚本中的文本文件中获取随机行,而不是如何编写 Python 脚本。 (2认同)

Mer*_*lin 5

我的首选选项非常快,我采样了一个带有 13 列、23.1M 行、2.0GB 未压缩的制表符分隔的数据文件。

# randomly sample select 5% of lines in file
# including header row, exclude blank lines, new seed

time \
awk 'BEGIN  {srand()} 
     !/^$/  { if (rand() <= .05 || FNR==1) print > "data-sample.txt"}' data.txt

# awk  tsv004  3.76s user 1.46s system 91% cpu 5.716 total
Run Code Online (Sandbox Code Playgroud)

  • 这太棒了——而且速度超级快。 (2认同)