Какой простой способ прочитать случайную строку из файла в командной строке Unix?
Вы можете использовать shuf
:
shuf -n 1 $FILE
Существует также утилита rl
. В Debian это в пакете randomize-lines
, который делает именно то, что вы хотите, хотя и не доступен во всех дистрибутивах. На своей домашней странице он рекомендует использовать вместо shuf
(чего не было, когда он был создан, я считаю). shuf
является частью GNU coreutils, rl
не является.
rl -c 1 $FILE
shuf
, она встроена в Fedora.
Другая альтернатива:
head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1
sort --random-sort $FILE | head -n 1
(Мне нравится, что подход shuf выше даже лучше - я даже не знал, что существует, и я бы никогда не нашел этот инструмент самостоятельно)
sort
, не работающая ни на одной из моих систем (CentOS 5.5, Mac OS 10.7.2). Кроме того, бесполезное использование cat может быть уменьшено до sort --random-sort < $FILE | head -n 1
sort -R <<< $'1\n1\n2' | head -1
скорее всего, вернет 1 и 2, потому что sort -R
сортирует повторяющиеся строки вместе. То же самое относится и к sort -Ru
, потому что он удаляет повторяющиеся строки.
perlfaq5: Как выбрать случайную строку из файла? Здесь используется алгоритм выборки коллектора из книги Camel:
$ perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' file
Это имеет существенное преимущество в пространстве над чтением всего файла. Вы можете найти доказательство этого метода в статье "Компьютерное программирование", том 2, раздел 3.4.2, Дональд Э. Кнут.
с помощью bash script:
#!/bin/bash
# replace with file to read
FILE=tmp.txt
# count number of lines
NUM=$(wc - l < ${FILE})
# generate random number in range 0-NUM
let X=${RANDOM} % ${NUM} + 1
# extract X-th line
sed -n ${X}p ${FILE}
Это просто.
cat file.txt | shuf -n 1
Конечно, это чуть медленнее, чем "shuf -n 1 file.txt" на нем.
-n 1
указывает 1 строку, и вы можете изменить ее на более чем 1. shuf
можно использовать и для других целей; Я просто передал ps aux
и grep
чтобы случайно убить процессы, частично совпадающие с именем.
Одиночная строка bash:
sed -n $((1+$RANDOM%`wc -l test.txt | cut -f 1 -d ' '`))p test.txt
Незначительная проблема: дублировать имя файла.
wc -l < test.txt
позволяет избежать необходимости cut
трубу.
Вот простой Python script, который выполнит задание:
import random, sys
lines = open(sys.argv[1]).readlines()
print(lines[random.randrange(len(lines))])
Использование:
python randline.py file_to_get_random_line_from
import random, sys lines = open(sys.argv[1]).readlines()
для i в диапазоне (len (линии)): rand = random.randint (0, len (линии) ) -1) print lines.pop (rand),
Другой способ: awk '
awk NR==$((${RANDOM} % `wc -l < file.name` + 1)) file.name
$RANDOM
- это bashism ). Вот чистый метод awk (mawk), использующий ту же логику, что и приведенный выше код perlfaq5 @ Tracker1: awk 'rand() * NR < 1 { line = $0 } END { print line }' file.name
(вау, он еще короче чем код perl!)
wc
), чтобы получить счетчик строк, а затем снова должен прочитать (часть) файл ( awk
), чтобы получить содержимое заданного случайного номера строки. Ввод / вывод будет намного дороже, чем получение случайного числа. Мой код читает файл только один раз. Проблема с awk rand()
состоит в том, что он затрачивается на основе секунд, поэтому вы получите дубликаты, если будете запускать их слишком быстро.
Решение, которое также работает на MacOSX, а также должно работать на Linux (?):
N=5
awk 'NR==FNR {lineN[$1]; next}(FNR in lineN)' <(jot -r $N 1 $(wc -l < $file)) $file
Где:
N
- количество случайных строк, которые вы хотите
NR==FNR {lineN[$1]; next}(FNR in lineN) file1 file2
- > сохранить номера строк, записанные в file1
, а затем напечатать соответствующую строку в file2
jot -r $N 1 $(wc -l < $file)
→ произвольно нарисовать N
числа (-r
) в диапазоне (1, number_of_line_in_file)
с помощью jot
. Подстановка процесса <()
сделает его похожим на файл для интерпретатора, поэтому file1
в предыдущем примере.Вот что я обнаружил, так как моя Mac OS не использует все легкие ответы. Я использовал команду jot для генерации числа, поскольку решения переменной $RANDOM кажутся не очень случайными в моем тесте. При тестировании моего решения у меня было большое разброс в решениях, представленных на выходе.
RANDOM1=`jot -r 1 1 235886`
#range of jot ( 1 235886 ) found from earlier wc -w /usr/share/dict/web2
echo $RANDOM1
head -n $RANDOM1 /usr/share/dict/web2 | tail -n 1
Эхо переменной - это визуализация генерируемого случайного числа.
#!/bin/bash
IFS=$'\n' wordsArray=($(<$1))
numWords=${#wordsArray[@]}
sizeOfNumWords=${#numWords}
while [ True ]
do
for ((i=0; i<$sizeOfNumWords; i++))
do
let ranNumArray[$i]=$(( ( $RANDOM % 10 ) + 1 ))-1
ranNumStr="$ranNumStr${ranNumArray[$i]}"
done
if [ $ranNumStr -le $numWords ]
then
break
fi
ranNumStr=""
done
noLeadZeroStr=$((10#$ranNumStr))
echo ${wordsArray[$noLeadZeroStr]}
Используя только vanilla sed и awk и без использования $RANDOM, простой, экономный по размеру и разумно быстрый "однострочный" для выбора одной строки псевдослучайно из файла с именем FILENAME выглядит следующим образом:
sed -n $(awk 'END {srand(); r=rand()*NR; if (r<NR) {sub(/\..*/,"",r); r++;}; print r}' FILENAME)p FILENAME
(Это работает, даже если FILENAME пуст, и в этом случае линия не испускается.)