
300個のデータファイルを含むディレクトリがあるとします。これらのファイルのうち200個をランダムに選択して別のディレクトリに移動したいと思います。 Unix / Linuxでこれを行う方法はありますか?
答え1
システムにこの機能があると、shuf
非常に便利に使用できます(見苦しいファイル名も処理できます)。
shuf -zen200 source/* | xargs -0 mv -t dest
そうではありませんが、それがかかる場合shuf
は、次のように動作します。sort
-R
find source -type f -print0 | sort -Rz | cut -d $'\0' -f-200 | xargs -0 mv -t dest
答え2
統計的ランダム性が必要な場合は使用しないでくださいRANDOM % ${#keys[@]}
。
$RANDOM
32768個の固有値があります。- 最初の選択は300要素のうちの1つです。
- 32768 = 109 * 300 + 68
したがって、最初の項目が選択された場合、最初の68要素のそれぞれは、選択される確率が110/32768~=0.33569%であり、残りの232要素はそれぞれ109/32768~=0.33264%の機会が選択されます。 。選択はさまざまな機会で複数回繰り返されますが、毎回最初の要素がバイアスされ、32768 % ${#keys[@]} -ne 0
エラーが複雑になります。
これは公平でなければなりませんで、すべてのファイル名で動作します。
while IFS= read -r -d '' -u 9
do
mv -- "$REPLY" /target/dir
done 9< <(find /source/dir -mindepth 1 -print0 | shuf -n 200 -z)
答え3
files=(*)
for (( i=0; i<200; i++ )); do
keys=("${!files[@]}")
rnd=$(( RANDOM % ${#keys[@]} ))
key=${keys[$rnd]}
mv "${files[$key]}" "$otherdir"
unset files[$key]
done
答え4
bashでは、すべてのファイル名を「files」という配列に入れます。
files=( * )
配列サイズ:
echo ${#files[@]}
そのうちの3分の2をサンプルサイズとして定義します。
take=$((2*${#files[@]}/3))
for i in $(seq 1 $take)
do
r=$((RANDOM%${#files[@]}))
echo ${files[r]}
done
これで重複項目が選択されます。はいスペースなどを含むファイル名ではテストされていません。
重複を避ける最も簡単な方法は、すべてのファイルを繰り返し、2/3の確率で各ファイルを選択することです。ただし、これは必ずしも200個のファイルが生成されるわけではありません。
リストからファイルを選択し、要件を満たすと、ファイルは削除されます。
#!/bin/bash
files=( * )
# define 2/3 of them as sample size:
take=$((2*${#files[@]}/3))
while (( i < $take ))
do
r=$((RANDOM%${#files[@]}))
f=${files[r]}
if [[ -n $f ]]
then
i=$((i+1))
echo ${files[r]}
unset files[r]
fi
done