Круто, не знал сортировки -R; Я использовал bogosort ранее :-p
alex
5
sort: неверный параметр - R Попробуйте `sort --help 'для получения дополнительной информации.
2
Кажется, не работает для файлов, в которых есть пробелы.
Houshalter
Это должно работать для файлов с пробелами (конвейер обрабатывает строки). Это не работает для имен с новой строкой в них. Только использование "$file", не показанное, будет чувствительным к пробелам.
Вы можете использовать shuf(из пакета GNU coreutils) для этого. Просто напишите ему список имен файлов и попросите вернуть первую строку из случайной перестановки:
ls dirname | shuf -n 1# probably faster and more flexible:
find dirname -type f | shuf -n 1# etc..
Отрегулируйте -n, --head-count=COUNTзначение, чтобы получить количество искомых строк. Например, чтобы вернуть 5 случайных имен файлов, вы бы использовали:
ОП хотел выбрать Nслучайные файлы, поэтому использование 1немного вводит в заблуждение.
aioobe
4
Если у вас есть имена файлов с символами новой строки:find dirname -type f -print0 | shuf -zn1
Hitechcomputergeek
5
Что делать, если мне нужно скопировать эти случайно выбранные файлы в другую папку? как выполнять операции с этими случайно выбранными файлами?
Ришабх Аграри
18
Вот несколько возможностей, которые не анализируют выходные данные lsи которые на 100% безопасны для файлов с пробелами и забавными символами в их имени. Все они будут заполнять массив randfсписком случайных файлов. Этот массив легко распечатывается printf '%s\n' "${randf[@]}"при необходимости.
Этот файл, возможно, будет выводить один и тот же файл несколько раз, и его Nнеобходимо знать заранее. Здесь я выбрал N = 42.
a=(*)
randf=("${a[RANDOM%${#a[@]}]"{1..42}"}")
Эта функция не очень хорошо задокументирована.
Если N не известно заранее, но вам действительно понравилась предыдущая возможность, вы можете использовать eval. Но это зло, и вы должны действительно убедиться, что Nэто не исходит от ввода пользователя без тщательной проверки!
Заметка . Это поздний ответ на старый пост, но принятый ответ ссылается на внешнюю страницу, которая показывает ужасныйударпрактика, и другой ответ не намного лучше, поскольку он также анализирует вывод ls. Комментарий к принятому ответу указывает на превосходный ответ Луната, который явно демонстрирует хорошую практику, но не совсем отвечает ОП.
Первый и второй произвели «плохую замену»; ему не нравилась "{1..42}"часть, оставляющая след "1". Кроме того, $RANDOMтолько 15 бит, и метод не будет работать с более чем 32767 файлами на выбор.
Вы не должны полагаться на вывод ls. Это не будет работать, если, например, имя файла содержит символы новой строки.
bfontaine
3
@bfontaine, кажется, вас преследуют переводы строк в именах файлов :). Они действительно так распространены? Другими словами, есть ли какой-нибудь инструмент, который создает файлы с символами новой строки в их имени? Поскольку как пользователь очень сложно создать такое имя файла. То же самое для файлов, поступающих из Интернета
Ciprian Tomoiagă
3
@CiprianTomoiaga Это пример проблем, которые вы можете получить. lsНе гарантируется, что вы получите «чистые» имена файлов, поэтому вам не следует полагаться на это, точка. Тот факт, что эти проблемы редки или необычны, не меняет проблему; особенно учитывая, что есть лучшие решения для этого.
bfontaine
lsможет включать в себя каталоги и пустые строки. Я бы предложил что-то вроде find . -type f | shuf -n10этого.
Чердт
9
Простое решение для выбора 5случайных файлов, избегая при этом разбора ls . Он также работает с файлами, содержащими пробелы, символы новой строки и другие специальные символы:
shuf -ezn 5*| xargs -0-n1 echo
Замените echoна команду, которую вы хотите выполнить для ваших файлов.
ну разве труба + не readимеет тех же проблем, что и разбор ls? а именно, он читает строку за строкой, поэтому он не работает для файлов с символами новой строки в их имени
Ciprian Tomoiagă
3
Ты прав. Мое предыдущее решение не работало для имен файлов, содержащих символы новой строки, и, возможно, для других также использовались определенные специальные символы. Я обновил свой ответ, чтобы использовать нулевое окончание вместо новых строк.
Scai
4
Если у вас установлен Python (работает с Python 2 или Python 3):
Чтобы выбрать один файл (или строку из произвольной команды), используйте
ls -1| python -c "import sys; import random; print(random.choice(sys.stdin.readlines()).rstrip())"
Чтобы выбрать Nфайлы / строки, используйте (примечание Nв конце команды, замените это числом)
ls -1| python -c "import sys; import random; print(''.join(random.sample(sys.stdin.readlines(), int(sys.argv[1]))).rstrip())" N
Это не работает, если ваше имя файла содержит символы новой строки.
bfontaine
4
Это еще более поздний ответ на поздний ответ @ gniourf_gniourf, за который я только что проголосовал, потому что это, безусловно, лучший ответ, дважды. (Один раз для избежания evalи один раз для безопасной обработки имени файла.)
Но мне потребовалось несколько минут, чтобы распутать «не очень хорошо документированные» функции, которые использует этот ответ. Если ваши навыки Bash достаточно сильны, чтобы вы сразу увидели, как это работает, пропустите этот комментарий. Но я этого не сделал, и, распутав это, думаю, это стоит объяснить.
Особенностью # 1 является собственное копирование файлов оболочки. a=(*)создает массив, $aчленами которого являются файлы в текущем каталоге. Bash понимает все странности имен файлов, поэтому список гарантированно корректен, гарантированно экранирован и т. Д. Не нужно беспокоиться о правильном разборе имен текстовых файлов, возвращаемых ls.
Особенностью # 2 является расширение параметров Bash для массивов , один вложенный в другой. Это начинается с того ${#ARRAY[@]}, что расширяется до длины $ARRAY.
Это расширение затем используется для индексации массива. Стандартный способ найти случайное число от 1 до N состоит в том, чтобы взять значение случайного числа по модулю N. Нам нужно случайное число от 0 до длины нашего массива. Вот подход, разбитый на две строки для ясности:
LENGTH=${#ARRAY[@]}
RANDOM=${a[RANDOM%$LENGTH]}
Но это решение делает это в одной строке, удаляя ненужное присвоение переменной.
Особенностью # 3 является расширение Bash Brace , хотя я должен признаться, что не совсем понимаю. Фигурные скобки используются, например, для формирования списка из 25 файлов с именами filename1.txt, filename2.txtи т.д.: echo "filename"{1..25}".txt".
Выражение внутри подоболочки выше "${a[RANDOM%${#a[@]}]"{1..42}"}"использует этот трюк для создания 42 отдельных расширений. Расширение фигурных скобок помещает одну цифру между ]и }, которая, как я сначала думал, подписывает массив, но если это так, ему предшествует двоеточие. (Он также возвратил бы 42 последовательных элемента из случайного места в массиве, что совсем не то же самое, что вернуть 42 случайных элемента из массива.) Я думаю, что это просто заставляет оболочку запускать расширение 42 раза, возвращая тем самым 42 случайных элемента из массива. (Но если кто-то может объяснить это более полно, я бы хотел услышать это.)
Причина, по которой N должен быть жестко задан (до 42), заключается в том, что расширение скобки происходит до расширения переменной.
Наконец, вот функция № 4 , если вы хотите сделать это рекурсивно для иерархии каталогов:
shopt -s globstar
a=(**)
Это включает параметр оболочки, который вызывает **рекурсивное совпадение. Теперь ваш $aмассив содержит каждый файл во всей иерархии.
Здесь я хотел скопировать файлы, но если вы хотите переместить файлы или сделать что-то еще, просто измените последнюю команду, которую я использовал cp.
#!/bin/bash# Reads a given directory and picks a random file.# The directory you want to use. You could use "$1" instead if you# wanted to parametrize it.
DIR="/path/to/"# DIR="$1"# Internal Field Separator set to newline, so file names with# spaces do not break our script.
IFS='
'if[[-d "${DIR}"]]then# Runs ls on the given dir, and dumps the output into a matrix,# it uses the new lines character as a field delimiter, as explained above.# file_matrix=($(ls -LR "${DIR}"))
file_matrix=($(ls -R $DIR | awk '; /:$/&&f{s=$0;f=0}; /:$/&&!f{sub(/:$/,"");s=$0;f=1;next}; NF&&f{ print s"/"$0 }'))
num_files=${#file_matrix[*]}# This is the command you want to run on a random file.# Change "ls -l" by anything you want, it's just an example.
ls -l "${file_matrix[$((RANDOM%num_files))]}"fi
exit 0
В MacOS нет команд sort -R и shuf , поэтому мне понадобилось решение только для bash, которое рандомизирует все файлы без дубликатов и не нашло его здесь. Это решение похоже на решение № 4 от gniourf_gniourf, но, надеюсь, добавляет лучшие комментарии.
Сценарий должен быть легко модифицирован для остановки после N выборок с использованием счетчика с if или цикла gniourf_gniourf's for с N. $ RANDOM ограничен ~ 32000 файлами, но это должно быть в большинстве случаев.
#!/bin/bash
array=(*)# this is the array of files to shuffle# echo ${array[@]}for dummy in"${array[@]}";do# do loop length(array) times; once for each file
length=${#array[@]}
randomi=$(( $RANDOM % $length ))# select a random index
filename=${array[$randomi]}
echo "Processing: '$filename'"# do something with the file
unset -v "array[$randomi]"# set the element at index $randomi to NULL
array=("${array[@]}")# remove NULL elements introduced by unset; copy arraydone
ls | shuf -n 5
Источник от Unix StackexchangeОтветы:
Вот скрипт, который использует случайную опцию сортировки GNU:
источник
"$file"
, не показанное, будет чувствительным к пробелам.ls
?Вы можете использовать
shuf
(из пакета GNU coreutils) для этого. Просто напишите ему список имен файлов и попросите вернуть первую строку из случайной перестановки:Отрегулируйте
-n, --head-count=COUNT
значение, чтобы получить количество искомых строк. Например, чтобы вернуть 5 случайных имен файлов, вы бы использовали:источник
N
случайные файлы, поэтому использование1
немного вводит в заблуждение.find dirname -type f -print0 | shuf -zn1
Вот несколько возможностей, которые не анализируют выходные данные
ls
и которые на 100% безопасны для файлов с пробелами и забавными символами в их имени. Все они будут заполнять массивrandf
списком случайных файлов. Этот массив легко распечатываетсяprintf '%s\n' "${randf[@]}"
при необходимости.Этот файл, возможно, будет выводить один и тот же файл несколько раз, и его
N
необходимо знать заранее. Здесь я выбрал N = 42.Эта функция не очень хорошо задокументирована.
Если N не известно заранее, но вам действительно понравилась предыдущая возможность, вы можете использовать
eval
. Но это зло, и вы должны действительно убедиться, чтоN
это не исходит от ввода пользователя без тщательной проверки!Мне лично не нравится
eval
и отсюда этот ответ!То же самое, используя более простой метод (цикл):
Если вы не хотите иметь один и тот же файл несколько раз:
Заметка . Это поздний ответ на старый пост, но принятый ответ ссылается на внешнюю страницу, которая показывает ужасныйударпрактика, и другой ответ не намного лучше, поскольку он также анализирует вывод
ls
. Комментарий к принятому ответу указывает на превосходный ответ Луната, который явно демонстрирует хорошую практику, но не совсем отвечает ОП.источник
"{1..42}"
часть, оставляющая след"1"
. Кроме того,$RANDOM
только 15 бит, и метод не будет работать с более чем 32767 файлами на выбор.источник
ls
. Это не будет работать, если, например, имя файла содержит символы новой строки.ls
Не гарантируется, что вы получите «чистые» имена файлов, поэтому вам не следует полагаться на это, точка. Тот факт, что эти проблемы редки или необычны, не меняет проблему; особенно учитывая, что есть лучшие решения для этого.ls
может включать в себя каталоги и пустые строки. Я бы предложил что-то вродеfind . -type f | shuf -n10
этого.Простое решение для выбора
5
случайных файлов, избегая при этом разбора ls . Он также работает с файлами, содержащими пробелы, символы новой строки и другие специальные символы:Замените
echo
на команду, которую вы хотите выполнить для ваших файлов.источник
read
имеет тех же проблем, что и разборls
? а именно, он читает строку за строкой, поэтому он не работает для файлов с символами новой строки в их имениЕсли у вас установлен Python (работает с Python 2 или Python 3):
Чтобы выбрать один файл (или строку из произвольной команды), используйте
Чтобы выбрать
N
файлы / строки, используйте (примечаниеN
в конце команды, замените это числом)источник
Это еще более поздний ответ на поздний ответ @ gniourf_gniourf, за который я только что проголосовал, потому что это, безусловно, лучший ответ, дважды. (Один раз для избежания
eval
и один раз для безопасной обработки имени файла.)Но мне потребовалось несколько минут, чтобы распутать «не очень хорошо документированные» функции, которые использует этот ответ. Если ваши навыки Bash достаточно сильны, чтобы вы сразу увидели, как это работает, пропустите этот комментарий. Но я этого не сделал, и, распутав это, думаю, это стоит объяснить.
Особенностью # 1 является собственное копирование файлов оболочки.
a=(*)
создает массив,$a
членами которого являются файлы в текущем каталоге. Bash понимает все странности имен файлов, поэтому список гарантированно корректен, гарантированно экранирован и т. Д. Не нужно беспокоиться о правильном разборе имен текстовых файлов, возвращаемыхls
.Особенностью # 2 является расширение параметров Bash для массивов , один вложенный в другой. Это начинается с того
${#ARRAY[@]}
, что расширяется до длины$ARRAY
.Это расширение затем используется для индексации массива. Стандартный способ найти случайное число от 1 до N состоит в том, чтобы взять значение случайного числа по модулю N. Нам нужно случайное число от 0 до длины нашего массива. Вот подход, разбитый на две строки для ясности:
Но это решение делает это в одной строке, удаляя ненужное присвоение переменной.
Особенностью # 3 является расширение Bash Brace , хотя я должен признаться, что не совсем понимаю. Фигурные скобки используются, например, для формирования списка из 25 файлов с именами
filename1.txt
,filename2.txt
и т.д.:echo "filename"{1..25}".txt"
.Выражение внутри подоболочки выше
"${a[RANDOM%${#a[@]}]"{1..42}"}"
использует этот трюк для создания 42 отдельных расширений. Расширение фигурных скобок помещает одну цифру между]
и}
, которая, как я сначала думал, подписывает массив, но если это так, ему предшествует двоеточие. (Он также возвратил бы 42 последовательных элемента из случайного места в массиве, что совсем не то же самое, что вернуть 42 случайных элемента из массива.) Я думаю, что это просто заставляет оболочку запускать расширение 42 раза, возвращая тем самым 42 случайных элемента из массива. (Но если кто-то может объяснить это более полно, я бы хотел услышать это.)Причина, по которой N должен быть жестко задан (до 42), заключается в том, что расширение скобки происходит до расширения переменной.
Наконец, вот функция № 4 , если вы хотите сделать это рекурсивно для иерархии каталогов:
Это включает параметр оболочки, который вызывает
**
рекурсивное совпадение. Теперь ваш$a
массив содержит каждый файл во всей иерархии.источник
Если у вас есть больше файлов в вашей папке, вы можете использовать приведенную ниже команду, которую я нашел в unix stackexchange .
Здесь я хотел скопировать файлы, но если вы хотите переместить файлы или сделать что-то еще, просто измените последнюю команду, которую я использовал
cp
.источник
Это единственный скрипт, который я могу хорошо сыграть с bash на MacOS. Я соединил и отредактировал фрагменты из следующих двух ссылок:
Команда ls: как получить рекурсивный полный путь, по одной строке на файл?
http://www.linuxquestions.org/questions/linux-general-1/is-there-a-bash-command-for-picking-a-random-file-678687/
источник
В MacOS нет команд sort -R и shuf , поэтому мне понадобилось решение только для bash, которое рандомизирует все файлы без дубликатов и не нашло его здесь. Это решение похоже на решение № 4 от gniourf_gniourf, но, надеюсь, добавляет лучшие комментарии.
Сценарий должен быть легко модифицирован для остановки после N выборок с использованием счетчика с if или цикла gniourf_gniourf's for с N. $ RANDOM ограничен ~ 32000 файлами, но это должно быть в большинстве случаев.
источник
Я использую это: он использует временный файл, но идет глубоко в каталог, пока не найдет обычный файл и не вернет его.
источник
Как насчет решения Perl, слегка подправленного мистером Кангом, здесь:
как я могу перетасовать строки текстового файла в командной строке Unix или в сценарии оболочки?
источник