在shell脚本中从文件中读取随机行有什么简单的方法?


当前回答

这很简单。

cat file.txt | shuf -n 1

当然,这只是比“shuf -n 1 file.txt”本身稍微慢一点。

其他回答

perlfaq5:我如何从文件中选择一个随机的行?下面是Camel Book上的一个油藏采样算法:

perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' file

与读取整个文件相比,这在空间上有很大的优势。你可以在Donald E. Knuth的《计算机编程艺术》第2卷第3.4.2节中找到这种方法的证明。

#!/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]}

这很简单。

cat file.txt | shuf -n 1

当然,这只是比“shuf -n 1 file.txt”本身稍微慢一点。

只使用普通sed和awk,不使用$RANDOM,一个简单、节省空间和合理快速的“一行程序”可以从文件名FILENAME中伪随机地选择一行,如下所示:

sed -n $(awk 'END {srand(); r=rand()*NR; if (r<NR) {sub(/\..*/,"",r); r++;}; print r}' FILENAME)p FILENAME

(即使FILENAME为空也能工作,在这种情况下不会触发任何行。)

这种方法的一个可能的优点是它只调用rand()一次。

正如@AdamKatz在评论中指出的,另一种可能是为每一行调用rand():

awk 'rand() * NR < 1 { line = $0 } END { print line }' FILENAME

(基于归纳法可以给出简单的正确性证明。)

关于rand的警告()

在大多数awk实现中,包括gawk, rand()每次运行awk时都从相同的起始数字或种子开始生成数字。

——https://www.gnu.org/software/gawk/manual/html_node/Numeric-Functions.html

单个bash行:

sed -n $((1+$RANDOM%`wc -l test.txt | cut -f 1 -d ' '`))p test.txt

小问题:重复的文件名。