Мой скрипт выдает тот же результат при использовании $ RANDOM

8

Я пытаюсь напечатать случайное nбуквенное слово, которое вводится nиз самой командной строки, но по какой-то причине мой сценарий дает мне один и тот же ответ каждый раз, когда используется одно и то же значение для n.

#!/bin/bash                                                                                                                                       
num=$1
egrep "^.{$num}$" /usr/share/dict/words | head -n $RANDOM| tail -n 1

Я называю свой сценарий так:

$ bash var3.sh 5
étude             # always the same output when using 5 

$ bash var3.sh 3
zoo               # always the same output when using 3

где var3.sh- имя моего сценария, а 5 - длина слова, которое я хочу напечатать случайным образом.

Как заставить его напечатать действительно случайное слово?

Каран Сингх
источник
3
$RANDOMскорее всего, будет больше, чем количество n- буквенных слов для большинства значений n (95,7% времени для n = 3 для меня).
Майкл Гомер
Вы хотите напечатать случайное слово полностью, даже если это не слово, или распечатать случайно из слова?
iZodiac
Если ваша задача связана с безопасностью (например, для создания пароля), вам следует использовать инструмент, созданный для этой задачи. В противном случае, можно использовать shufили sort -Rкак предложено в ответах. Вы также можете использовать $RANDOM, но более продвинутым способом. Все эти инструменты дают результаты, которые можно прогнозировать (они не являются действительно случайными), но они быстры и достаточно хороши для многих целей.
Судодус
1
Может быть, они используют этот метод (обязательная ссылка на XKCD)
molnarm

Ответы:

20

Это не так. Но $ RANDOM возвращает большие числа (от 0 до 32767), которые, особенно для слов ограниченной длины, показывают тот же результат, так как headчасть, вероятно, возвращает все результаты grep (для 3, в my только 819 совпадений /usr/share/dict/words).

Лучшим решением может быть перемешать результаты:

egrep "^.{$num}$" /usr/share/dict/words | sort -R | tail -n 1

где -Rозначает --random-sort( sortрасширение GNU ).

Якуб Лаки
источник
16
Почему tail? Это имело смысл в сценарии OP, но поскольку вы тасуете, вы также можете использовать head, а затем sortдолжны быть в состоянии обнаружить сломанную трубу и не беспокоиться о перетасовке остальных строк.
Питер Тейлор
@PeterTaylor, вероятно, хороший совет. Использование хвоста - моя привычка ... В конце концов, я бы предпочел еще больше shuf -n1, что на одну трубу меньше ...
Якуб Лаки
19

Простой метод для печати произвольного num- буквенного слова использует shuf:

egrep "^.{$num}$" /usr/share/dict | shuf -n1

Команда shufвыводит случайную перестановку входных данных, и -n1флаг указывает, что из этого результата нужно вывести только первый элемент.

Лиса
источник
3
или grep -Ex ".{$num}". Или awk 'length == n' n="$num"'.
Стефан Шазелас
5

Как уже отмечали другие, основная проблема с вашим кодом заключается в том, что $RANDOMчаще всего это значение будет намного больше, чем количество слов определенной длины.

Используя awkтолько:

$ awk -v len="$num" 'length == len { word[i++]=$0 }
                     END { print word[int(i*rand())] }' /usr/share/dict/words
Bosniac

Программа читает все строки данного файла определенной длины. Они хранятся в массиве words.

В конце случайный элемент из этого массива выбирается и печатается.

Кусалананда
источник