当前位置: 首页>>技术教程>>正文


scripts – 如何显示文本文件中的随机行?

,

问题描述

我正在尝试写一个shell脚本。这个想法是从文本文件中随机选择一行并将其显示为 Ubuntu 桌面通知。

但我希望每次执行脚本时选择不同的行。有什么解决方案可以做到这一点吗?我不想要整个剧本。只是这么简单的事情而已。

最佳回答

您可以使用 shuf 实用程序从文件中打印随机行

$ shuf -n 1 filename

-n :要打印的行数

例子:

$ shuf -n 1 /etc/passwd

git:x:998:998:git daemon user:/:/bin/bash

$ shuf -n 2 /etc/passwd

avahi:x:84:84:avahi:/:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false

次佳回答

您还可以使用 sort 命令从文件中获取随机行。

sort -R filename | head -n1

第三种回答

只是为了好玩,这里是一个纯粹的 bash 解决方案,它不使用 shufsortwcsedheadtail 或任何其他外部工具。

shuf 变体相比,唯一的优点是它稍微快一些,因为它是纯 bash。在我的机器上,对于 1000 行的文件,shuf 变体大约需要 0.1 秒,而以下脚本大约需要 0.01 秒;)因此,虽然 shuf 是最简单和最短的变体,但速度更快。

老实说,我仍然会选择 shuf 解决方案,除非高效率是一个重要的考虑因素。

#!/bin/bash

FILE=file.txt

# get line count for $FILE (simulate 'wc -l')
lc=0
while read -r line; do
 ((lc++))
done < $FILE

# get a random number between 1 and $lc
rnd=$RANDOM
let "rnd %= $lc"
((rnd++))

# traverse file and find line number $rnd
i=0
while read -r line; do
 ((i++))
 [ $i -eq $rnd ] && break
done < $FILE

# output random line
printf '%s\n' "$line"

第四种回答

假设您有文件 notifications.txt 。我们需要计算总行数,以确定随机生成器的范围:

$ cat notifications.txt | wc -l

让我们写入变量:

$ LINES=$(cat notifications.txt | wc -l)

现在要生成从 0$LINE 的数字,我们将使用 RANDOM 变量。

$ echo $[ $RANDOM % LINES]

让我们将其写入变量:

$  R_LINE=$(($RANDOM % LINES))

现在我们只需要打印这个行号:

$ sed -n "${R_LINE}p" notifications.txt

关于随机:

   RANDOM Each time this parameter is referenced, a random integer between
          0 and 32767 is generated.  The sequence of random numbers may be
          initialized by assigning a value to RANDOM.  If RANDOM is unset,
          it  loses  its  special  properties,  even if it is subsequently
          reset.

确保您的文件的行号少于 32767。如果您需要开箱即用的更大随机生成器,请参阅 this

例子:

$ od -A n -t d -N 3 /dev/urandom | tr -d ' '

第五种回答

下面是一个从输入文件或标准输入中选择随机行的 Python 脚本:

#!/usr/bin/env python
"""Usage: select-random [<file>]..."""
import random

def select_random(iterable, default=None, random=random):
    """Select a random element from iterable.

    Return default if iterable is empty.
    If iterable is a sequence then random.choice() is used for efficiency instead.
    If iterable is an iterator; it is exhausted.
    O(n)-time, O(1)-space algorithm.
    """
    try:
        return random.choice(iterable) # O(1) time and space
    except IndexError: # empty sequence
        return default
    except TypeError: # not a sequence
        return select_random_it(iter(iterable), default, random.randrange)

def select_random_it(iterator, default=None, randrange=random.randrange):
    """Return a random element from iterator.

    Return default if iterator is empty.
    iterator is exhausted.
    O(n)-time, O(1)-space algorithm.
    """
    # from https://stackoverflow.com/a/1456750/4279
    # select 1st item with probability 100% (if input is one item, return it)
    # select 2nd item with probability 50% (or 50% the selection stays the 1st)
    # select 3rd item with probability 33.(3)%
    # select nth item with probability 1/n
    selection = default
    for i, item in enumerate(iterator, start=1):
        if randrange(i) == 0: # random [0..i)
            selection = item
    return selection

if __name__ == "__main__":
    import fileinput
    import sys

    random_line = select_random_it(fileinput.input(), '\n')
    sys.stdout.write(random_line)
    if not random_line.endswith('\n'):
        sys.stdout.write('\n') # always append newline at the end

该算法的时间复杂度为 O(n),空间复杂度为 O(1)。它适用于大于 32767 行的文件。它不会将输入文件加载到内存中。它只读取每个输入行一次,即您可以将任意大(但有限)的内容通过管道传输到其中。这是 explanation of the algorithm

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/13825.html,未经允许,请勿转载。