Вот фрагмент оболочки, который опирается только на функции POSIX и справляется с произвольными именами файлов (но в выборке пропускает точечные файлы). Случайный выбор использует awk, потому что это все, что вы получаете в POSIX. Это очень плохой генератор случайных чисел, так как RNG в awk засеивается с текущим временем в секундах (поэтому он легко предсказуем и возвращает тот же выбор, если вы вызываете его несколько раз в секунду).
set -- *
n=$(echo $# | awk '{srand(); print int(rand()*$0) + 1}')
eval "file=\$$n"
echo "Processing $file"
Если вы не хотите игнорировать точечные файлы, код генерации имени файла (set -- *
) необходимо заменить чем-то более сложным.
set -- *; [ -e "$1" ] || shift
set .[!.]* "$@"; [ -e "$1" ] || shift
set ..?* "$@"; [ -e "$1" ] || shift
if [ $# -eq 0]; then echo 1>&2 "empty directory"; exit 1; fi
Если у вас есть OpenSSL, вы можете использовать его для генерации случайных байтов. Если у вас нет, но в вашей системе установлено значение /dev/urandom
, замените вызов на openssl
на dd if=/dev/urandom bs=3 count=1 2>/dev/null
. Вот фрагмент, который устанавливает n
в случайное значение между 1 и $#
, стараясь не вносить смещение. В этом фрагменте предполагается, что $#
не более 2 ^ 23-1.
while
n=$(($(openssl rand 3 | od -An -t u4) + 1))
[ $n -gt $((16777216 / $# * $#)) ]
do :; done
n=$((n % $#))