我正在尝试编写一个shell脚本。这个想法是从文本文件中随机选择一行,并将其显示为Ubuntu桌面通知。
但是我希望每次执行脚本时都选择不同的行。有解决方案吗?我不要整个剧本。只是那简单的事情而已。
我正在尝试编写一个shell脚本。这个想法是从文本文件中随机选择一行,并将其显示为Ubuntu桌面通知。
但是我希望每次执行脚本时都选择不同的行。有解决方案吗?我不要整个剧本。只是那简单的事情而已。
Answers:
您可以使用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/falsen表示要打印的行数。(即,您只需要一行还是两行)。不是行号(即第一行第二行)。
                    date +%S)为变量x,然后选择使用的是第x线head和tail命令从文本文件中。无论如何,您的方法更容易。谢谢
                    shuf在coreutils中,因此默认情况下可用。注意:它将输入文件加载到内存中。有一种不需要的有效算法。
                    只是为了好玩,这里是一个纯bash的解决方案不使用shuf,sort,wc,sed,head,tail或任何其他外部工具。
相对于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"shuf无论如何,使用会更好。考虑到这一点,我不相信纯粹的bash实际上比shuf我以前写过的效率更高。触发外部工具时可能会有最微小(恒定)的开销,但是它比解释的bash快得多。因此,shuf当然可以更好地扩展。因此,假设该脚本用于教育目的:很高兴看到它可以完成;)
                    shufGNU Coreutils是特定的(例如,不在FreeBSD 10.0中)。sort -R是可移植的,但是解决了一个不同的(相关)问题:以多行出现的字符串的概率等于只出现一次的字符串的概率。(当然,wc仍然可以使用其他实用程序。)我认为这里的主要限制是,它永远不会在第32768行之后选择任何东西(并且随机性会更快些)。
                    $((RANDOM<<15|RANDOM))位于0..2 ^ 30-1。@JFSebastian 偏向更频繁的输入是shuf,而不是sort -R。将shuf -n 1代替sort -R | head -n1和比较。(顺便说一下,10 ^ 3迭代比10 ^ 6更快,但仍然足以显示出差异。)另请参见更粗略,更直观的演示,这有点愚蠢,表明它适用于所有字符串都是高频的大型输入。
                    dieharder似乎全为零。假设这不仅仅是我个人的一个奇怪错误,那肯定可以解释为什么它不是随机的!如果您运行while echo $(( RANDOM << 17 | RANDOM << 2 | RANDOM >> 13 )); do :; done | perl -ne 'print pack "I>"' > out了一段时间,然后out使用十六进制编辑器检查的内容,是否能获得美观的数据?(或者查看其他但是你喜欢。)我得到的所有零,而RANDOM不是罪魁祸首:我得到的所有零,当我更换$(( RANDOM << 17 | RANDOM << 2 | RANDOM >> 13 ))使用100了。
                    说您有文件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:
   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。见这个,如果你需要更大的随机生成的作品的开箱即用。
例:
$ od -A n -t d -N 3 /dev/urandom | tr -d ' 'LINES=$(wc -l < file.txt); R_LINE=$((RANDOM % LINES)); sed -n "${R_LINE}p" file.txt
                    这是一个Python脚本,可从输入文件或stdin中选择一条随机行:
#!/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 /programming//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行的文件。它不会将输入文件加载到内存中。它只读取一次每个输入行,即,您可以通过管道将任意大(但有限)的内容输入其中。这是该算法的说明。
马尔特·斯科鲁帕(Malte Skoruppa)和其他人所做的工作给我留下了深刻的印象,但这是一种更简单的“纯重打击”方法:
IFS=$'\012'
# set field separator to newline only
lines=( $(<test5) )
# slurp entire file into an array
numlines=${#lines[@]}
# count the array elements
num=$(( $RANDOM$RANDOM$RANDOM % numlines ))
# get a (more-or-less) random number within the correct range
line=${lines[$num]}
# select the element corresponding to the random number
echo $line
# display it如某些人所述,$ RANDOM不是随机的。但是,可以通过根据需要将$ RANDOM串在一起来克服32767行的文件大小限制。