web-dev-qa-db-ja.com

Unixコマンドラインでファイルからランダムな行を読み取る簡単な方法は何ですか?

Unixコマンドラインでファイルからランダムな行を読み取る簡単な方法は何ですか?

244
Newbie Prog

shufを使用できます:

shuf -n 1 $FILE

rlというユーティリティもあります。 Debianでは、randomize-linesパッケージ内にあり、すべてのディストリビューションで利用できるわけではありませんが、まさに必要なことを行います。ホームページでは、代わりにshufの使用を推奨しています(作成時には存在していなかったと思います)。 shufはGNU coreutilsの一部ですが、rlはそうではありません。

rl -c 1 $FILE
360
unbeknown

別の選択肢:

head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1
72
PolyThinker
sort --random-sort $FILE | head -n 1

(しかし、私は上記のshufアプローチがさらに好きです-それが存在することすら知らず、自分でそのツールを見つけたことがなかったでしょう)

これは簡単です。

cat file.txt | shuf -n 1

確かに、これは「shuf -n 1 file.txt」よりも少し遅いだけです。

29
Yokai

perlfaq5:ファイルからランダムな行を選択するにはどうすればよいですか? キャメルブックのリザーバーサンプリングアルゴリズムを次に示します。

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

これは、ファイル全体を読み取ることよりもスペースの点で大きな利点があります。ドナルドE.クヌースによるThe Art of Computer Programming、第2巻、セクション3.4.2にこの方法の証拠があります。

15
Tracker1

bashスクリプトを使用:

#!/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}
11
Paolo Tedesco

単一のbash行:

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

わずかな問題:ファイル名が重複しています。

4
asalamon74

以下は、仕事をする簡単なPythonスクリプトです。

import random, sys
lines = open(sys.argv[1]).readlines()
print(lines[random.randrange(len(lines))])

使用法:

python randline.py file_to_get_random_line_from
3
Adam Rosenfield

awk」を使用する別の方法

awk NR==$((${RANDOM} % `wc -l < file.name` + 1)) file.name
2
Baskar

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で範囲-rjot番号をランダムに((1, number_of_line_in_file))描画します。プロセスの置換<()は、インタープリターのファイルのように見えるため、前の例ではfile1になります。
1
jrjc

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が空の場合でも機能します。この場合、行は出力されません。)

このアプローチの利点の1つは、Rand()を1回だけ呼び出すことです。

コメントで@AdamKatzが指摘したように、別の可能性は、各行に対してRand()を呼び出すことです。

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

(帰納法に基づいて、正確さの簡単な証明を与えることができます。)

Rand()に関する注意

「gawkを含むほとんどのawk実装では、Rand()はawkを実行するたびに同じ開始番号またはシードから番号を生成し始めます。」

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

0
peak

Mac OSは簡単な答えをすべて使用しているわけではないので、ここに私が発見したものを示します。私のテストでは、$ RANDOM変数の解はランダムではないようであるため、jotコマンドを使用して数値を生成しました。ソリューションをテストするとき、出力で提供されるソリューションに大きなばらつきがありました。

  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

変数のエコーは、生成された乱数のビジュアルを取得することです。

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