Как-то раз, мне понадобился скрипт который бы сам выбирал рандомные файлы из директории. Собственно, я написал его и сейчас выложу здесь.
На для начала разберемся как будем это делать. Итак, на входе подается список директорий, в которых лежат нужные нам файлы. Собираем файлы и пихаем в массив. Перемешиваем все файлы в массиве (тогда при последовательном обходе они станут случайными). И все. Очень просто. На самом деле мой скрипт немного сложнее, но весь алгоритм такой.
Вот код:
shuf -e ${filesArray[@]}
Проблема в том, что shuf не входит в POSIX.
Еще можно попробовать делать это через sort -R.
Вот и все.
На для начала разберемся как будем это делать. Итак, на входе подается список директорий, в которых лежат нужные нам файлы. Собираем файлы и пихаем в массив. Перемешиваем все файлы в массиве (тогда при последовательном обходе они станут случайными). И все. Очень просто. На самом деле мой скрипт немного сложнее, но весь алгоритм такой.
Вот код:
#!/bin/bash onSIGINT() { # создаем функцию которая будет завершать вечный цикл echo "SIGINT received, bye bye!" exit 0 } trap 'onSIGINT' INT # трап, вызывающий эту функцию на SIGINT regexType="posix-egrep" # переменная указывающая на то, какие регулярные выражения будет использовать утилита find regex=".*\.(mp3|flac)$" # сам шаблон регулярного выражения depth="u" # глубина поиска. u [unlimited] - не ограничена, может быть числом if [[ $# -eq 0 ]]; then # проверка. Если не получили аргументов, то выводим хелп и выходим echo "Usage: $0 [-d DEPTH] DIR1 [DIR2 [DIR3 [...]]]" exit 0 fi index=0 for i in `seq 1 $#`; do # цикл обработки аргументов командной строки arg=${!i} if [[ $bNextDepth -eq 1 ]]; then bNextDepth=0 if [[ $arg =~ ^[0-9]+$ ]]; then # по сути проверка - число ли depth или нет depth=$arg continue else echo "Missing value for -d." # ошибка. Юзер написал -d но не написал значение для него exit 1 fi fi if [ "$arg" = "-d" ]; then bNextDepth=1 if [[ $# -eq $i ]]; then echo "Missing value for -d." exit 1 fi continue fi if [ ! -d "$arg" ]; then # проверяем, действительно ли нам подали директорию? echo "Directory $arg does not exists." else dirList[$index]=$arg # сохраняем ее в массив let "index++" fi done # конец обработки аргументов командной строки if [[ ${#dirList[@]} -eq 0 ]]; then # если юзер глупый и не ввел не одну правильную директорию выходим, сообщая ошибку echo "No one correct directory has been found." exit 2 fi index=0 if [ "$depth" != "u" ]; then # если у нас в depth число depthArg="-maxdepth $depth" fi while read line do filesArray[$index]="$line" let "index++" done < <(find "${dirList[@]}" $depthArg -regextype "$regexType" -iregex "$regex" -type f) # когда я впервые увидел эту строку в одном примере, желание писать скрипты на баше у меня почти отпало. Спасибо людям на канале #gentoo-ru которые мне объяснили ее смысл. А про find я расскажу ниже. filesNum=${#filesArray[@]} echo "Found $filesNum files." let "filesNum--" # уменьшаем на 1. Потому что for в баше (в отличии от Си) выберет последний элемент тоже. while [ true ]; do for i in `seq 0 "$filesNum"`; do # цикл который перемешает массив let "rndPos = RANDOM % $filesNum" temp="${filesArray[$i]}" # в этих 3 строках меняем местами элементы filesArray[$i]="${filesArray[$rndPos]}" filesArray[$rndPos]="$temp" done for i in `seq 0 "$filesNum"`; do # собственно, цикл запускающий нашу программу с нужным аргументом /usr/bin/mplayer "${filesArray[$i]}" done done exit 0 # все
find "${dirList[@]}" $depthArg -regextype "$regexType" -iregex "$regex" -type f
-maxdepth N это параметр указывающий find'у, сколько раз надо проходить во вложенные директории (1 - ни разу не переходить).
Кстати, вместо блока кода
- Здесь ${dirList[@]} - массив корректных директорий который мы составили ранее.
- $depthArg (без кавычек) - два слова, первое - аргумент (-maxdepth), второе - его значение.
- $regexType - тип регулярного выражения.
- $regex - шаблон регулярного выражения по которому мы выбираем файлы из директории.
- -type f - указывает find'у то, что нас интересуют только реальные файлы.
-maxdepth N это параметр указывающий find'у, сколько раз надо проходить во вложенные директории (1 - ни разу не переходить).
Кстати, вместо блока кода
for i in `seq 0 "$filesNum"`; do
let "rndPos = RANDOM % $filesNum"
temp="${filesArray[$i]}"
filesArray[$i]="${filesArray[$rndPos]}"
filesArray[$rndPos]="$temp"
done
можно использовать утилиту shuf. То есть весь этот блок кода заменить на строку:shuf -e ${filesArray[@]}
Проблема в том, что shuf не входит в POSIX.
Еще можно попробовать делать это через sort -R.
Вот и все.
вот тебе задачка покруче: скрипт чтоб делал каталог музыки, музыка разбита на категории и подкатегории и под-подкатегории, количество уровней - разное, надо сделать папку с линками на все групы, но не альбомы
ОтветитьУдалитьТы молодец, чувак! Жаль, твой блог мне не попался, когда мы Linux в универе проходили.
ОтветитьУдалитьНу просто восхитительно!
ОтветитьУдалитьОчень хороший блог .. ;)) Я люблю его, потому что вы можете прийти к знаю, что многие вещи; ** поцелуев отправить польских **;
ОтветитьУдалить.......... (░)(░)
........(░)(♥)(░)
..........(░)(░)
............(.|./)
....(▒)(▒)..|/)(░)(░)
..(▒)(♥)(▒).(░)(♥)(░)
.....(▒)(▒)..|.(░)(░)
..................|/)
.............¯¯¯¯¯/
............. ) ¯¯¯(
............./▫◊ ◊▫
............/▫▫▫▫▫▫▫▫
.........../▫▪▫▪▫▪▫▪▫▫
.......... \_______/
Самый полезный блог из всех, которые я встречал. Пиши еще.
ОтветитьУдалитьСпасибо, пригодится.
ОтветитьУдалитьНу хоть где-то все доступно объясняют!
ОтветитьУдалитьзаставил меня почуствовать блондинкой
ОтветитьУдалитьБаш - полезный язык
ОтветитьУдалитьах ты ж шикарный =)
ОтветитьУдалитьгдеты раньше был?)))
давно искал нечто подобное (^_^)
ОтветитьУдалитьХуйня какая-то. Выясняем количество файлов, генерируем число, берем файл с индексом равным этому числу, все!
ОтветитьУдалитьСтрок пять.
Надо будет поставить на ноутбук иксось.
ОтветитьУдалитьLaserJet, и будут у нас случаи когда одни и те же файлы проходят чаще чем другие. Кроме того, если в моем скрипте убрать все проверки и фичу с заданием глубины аргументом, то будет тоже 5 строк.
ОтветитьУдалитьЭтот комментарий был удален администратором блога.
ОтветитьУдалитьЭтот комментарий был удален администратором блога.
ОтветитьУдалить