Как отобразить случайную строку из текстового файла?

[F1]
1
задан 19 September 2014 в 03:35

5 ответов

Вы также можете использовать команду sort для получения случайной строки из файла.

sort -R filename | head -n1
13
ответ дан 24 May 2018 в 03:36
  • 1
    note: sort -R производит разные результаты, чем shuf -n1 или select-random , если на входе имеются повторяющиеся строки. См. @ комментарий Элиака Кагана . – jfs 24 September 2014 в 21:37

Просто для удовольствия, вот чистое решение bash, которое не использует shuf, sort, wc, sed, head, tail или любые другие внешние инструменты. [!d0 ]

Единственным преимуществом по сравнению с вариантом shuf является то, что он немного быстрее, так как это чистый баш. На моей машине для файла из 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"
8
ответ дан 24 May 2018 в 03:36
  • 1
    @EliahKagan Спасибо за предложения и хорошие моменты. Я признаю, что есть довольно много угловых дел, на которые я не слишком много думал. Я написал это больше для удовольствия. В любом случае использование shuf намного лучше. Думая об этом, я не верю, что чистый баш действительно эффективнее, чем использование shuf, как я писал ранее. При запуске внешнего инструмента могут быть самые маленькие (постоянные) накладные расходы, но затем он будет работать быстрее, чем интерпретируется bash. Таким образом, shuf, конечно, лучше масштабируется. Итак, скажем, сценарий служит образовательной цели: приятно видеть, что это можно сделать;) – Malte Skoruppa 19 September 2014 в 01:35
  • 2
    У GNU / Linux / Un * x есть много очень хорошо проверенных на дороге колес, которые я бы не хотел изобретать, если только это не было чисто академическим упражнением. "Оболочка" предназначалось для сборки большого количества небольших частей, которые могут быть (повторно) собраны различными способами через вход / выход & amp; множество опций. Все остальное - плохая форма, если только для спорта (например, codegolf.stackexchange.com/tour ), и в этом случае играйте ...! – michael 19 September 2014 в 11:51
  • 3
    @michael_n Хотя "чистый баш" путь в основном полезен для обучения и модификации для других задач, это более разумно "для реального" чем может показаться. Bash широко доступен, но shuf GNU Coreutils - специфический (например, не во FreeBSD 10.0). sort -R переносима, но решает другую (связанную) проблему: строки, появляющиеся как несколько строк, имеют вероятность, равную вероятности появления только один раз. (Конечно, wc и другие утилиты все еще можно использовать.) Я думаю, что основное ограничение здесь заключается в том, что это никогда не выбирает ничего после 32768-й линии (и становится менее случайным раньше). – Eliah Kagan 19 September 2014 в 19:59
  • 4
    Malte Skoruppa: Я вижу, вы переместили вопрос bash PRNG в U & amp; L . Круто. Подсказка: $((RANDOM<<15|RANDOM)) находится в 0..2 ^ 30-1. @ J.F.Sebastian Это shuf, а не sort -R, что перекликается с более частыми входами. Положите shuf -n 1 вместо sort -R | head -n1 и сравните. (Итерации Btw 10 ^ 3 быстрее, чем 10 ^ 6, и все еще достаточно для того, чтобы показать разницу.) См. Также более грубую, более визуальную демонстрацию и , этот бит глупости, показывающий, что он работает на больших входы, где все строки имеют высокую частоту . – Eliah Kagan 24 September 2014 в 19:35
  • 5
    @ J.F.Sebastian. В этой команде вход в 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. – Eliah Kagan 26 September 2014 в 19:23

Предположим, у вас есть файл notifications.txt. Нам нужно подсчитать общее количество строк, чтобы определить диапазон случайного генератора:

$ cat notifications.txt | wc -l

Давайте напишем переменную:

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

Теперь, чтобы сгенерировать число от 0 до $LINE мы будем использовать переменную RANDOM.

$ echo $[ $RANDOM % LINES]

Давайте перепишем ее в переменную:

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

Теперь нам нужно только напечатать этот номер строки: [!d4 ]

$ 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 ' '
3
ответ дан 24 May 2018 в 03:36

Вот скрипт 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 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) -time, O (1) -пространство. Он работает для файлов размером более 32767 строк. Он не загружает входные файлы в память. Он считывает каждую строку ввода ровно один раз, т. Е. Вы можете передать в нее произвольное большое (но конечное) содержимое. Вот объяснение алгоритма.

2
ответ дан 24 May 2018 в 03:36

Меня впечатляет работа, которую 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 не случайным. Тем не менее, ограничение размера файла 32767 строк преодолевается путем наложения $ RANDOM вместе по мере необходимости.

0
ответ дан 24 May 2018 в 03:36

Другие вопросы по тегам:

Похожие вопросы: