web-dev-qa-db-ja.com

テキストファイルからランダムな行を表示する方法は?

シェルスクリプトを記述しようとしています。アイデアは、テキストファイルからランダムに1行を選択し、Ubuntuデスクトップ通知として表示することです。

ただし、スクリプトを実行するたびに異なる行を選択する必要があります。これを行う解決策はありますか?スクリプト全体は必要ありません。単純なことだけです。

23
Anandu M Das

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
37
aneeshep

sortコマンドを使用して、ファイルからランダムな行を取得することもできます。

sort -R filename | head -n1
13
g_p

ファイル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未満であることを確認してください。箱から出して動作するより大きなランダムジェネレータが必要な場合は、 this を参照してください。

例:

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

入力ファイルまたは標準入力からランダムな行を選択する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 __== "__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行を超えるファイルに対して機能します。入力ファイルをメモリにロードしません。各入力行を1回だけ読み取ります。つまり、任意の大きな(ただし有限の)コンテンツをそこにパイプできます。 アルゴリズムの説明 です。

2
jfs

Malte Skoruppaなどが行った作業には感心しましたが、ここではそれを行うためのはるかに単純な「純粋なbash」方法を示します。

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はランダムではありません。ただし、32767行のファイルサイズ制限は、必要に応じて$ RANDOMを連結することで克服されます。

1
Wastrel