Список X случайных файлов из каталога


14

Есть ли способ составить список, скажем, 30 случайных файлов из каталога, используя стандартные команды Linux? (в zsh)

Верхний ответ, описанный здесь , не работает для меня ( sortне распознает опцию -R)


Мне любопытно, на какой ОС вы работаете.
ixtmixilix

Ответы:


7

Поскольку вы упоминаете Zsh:

rand() REPLY=$RANDOM
print -rl -- *(o+rand[1,30])

Вы можете заменить, printскажем, ogg123и *сказать**/*.ogg


19

Попробуйте передать lsвывод shuf, например,

$ touch 1 2 3 4 5 6 7 8 9 0
$ ls | shuf -n 5
5
9
0 
8
1

-nФлаг определяет , сколько случайных файлы , которые вы хотите.


command not found(не установлено): /
Амелио Васкес-Рейна

Странно ... это должно быть частью coreutils. Если ваш coreutils старый, то команды там не будет.
Ренан

6
Это быстрый и грязный способ, и я бы тоже его использовал - для одноразового сценария. Для чего-либо более долговечного, избегайте анализа выводаls .
Янмезен

@janmoesen Я не знал об этом. Благодарность!
Ренан

@Renan Не каждый Unix имеет GNU coreutils, установленный по умолчанию.
Кусалананда

2

Это довольно легко решить с помощью чуть-чуть Perl. Выберите четыре файла случайным образом из текущего каталога:

perl -MList::Util=shuffle -e 'print shuffle(`ls`)' | head -n 4

Однако для производственного использования я бы пошел с расширенным сценарием, который не полагается на lsвывод, может принять любой dir, проверить ваши аргументы и т. Д. Обратите внимание, что сам случайный выбор по-прежнему состоит всего из нескольких строк.

#!/usr/bin/perl    
use strict;
use warnings;
use List::Util qw( shuffle );

if ( @ARGV < 2 ) {
    die "$0 - List n random files from a directory\n"
        . "Usage: perl $0 n dir\n";
}
my $n_random = shift;
my $dir_name = shift;
opendir(my $dh, $dir_name) || die "Can't open directory $dir_name: $!";

# Read in the filenames in the directory, skipping '.' and '..'
my @filenames = grep { !/^[.]{1,2}$/ } readdir($dh);
closedir $dh;

# Handle over-specified input
if ( $n_random > $#filenames ) {
    print "WARNING: More values requested ($n_random) than available files ("
          . @filenames . ") - truncating list\n";
    $n_random = @filenames;
}

# Randomise, extract and print the chosen filenames
foreach my $selected ( (shuffle(@filenames))[0..$n_random-1] ) {
    print "$selected\n";
}

Imho Perl-скрипт не является «стандартной командой Unix». Эту проблему легко решить с помощью любого языка сценариев высокого уровня, такого как Perl, Python или Ruby, но она более интересна, если она непосредственно в командной строке.
Gerrit

1
@gerrit - я понимаю твою точку зрения. Я предоставил это, потому что предпочтительный ответ (использование shuf) не был достаточен для OP. Что касается и не является стандартным Unix - Perl существует повсюду, и он решает проблему кратко и надежно. Если бы я дал это как однострочник Perl, это бы считалось «командной строкой»? Является ли тот факт, что Perl является мощным аргументом против существования этого ответа?
ire_and_curses

Я бы сказал, что это ответ на другой вопрос. Конечно, на любом полнофункциональном языке программирования эта проблема тривиальна, для меня интересная часть вопроса заключается в том, можно ли это сделать / без / прибегая к сценарию ~ 20 LOC; языки сценариев являются мощными, но я не думаю, что Perl классифицирует как команду (такую, как запрашивал OP; и нет, если бы вы дали 200-символьную командную строку для вызова Perl, я бы имел такое же мнение).
геррит

@gerrit - Возможно, я могу быть более ясным. Посмотрите на мое редактирование: perl -MList::Util=shuffle -e 'print shuffle(Ls )' | head -n 4Это больше похоже на то , что вы искали?
ire_and_curses

Да, я удалил свое пониженное голосование, которое по общему признанию было немного резким.
Gerrit

1

Простое решение, которое позволяет избежать анализа ls, а также работает с пробелами:

shuf -en 30 dir/* | while read file; do
    echo $file
done

Как видно из других комментариев, OP находится в системе без shuf.
Кусалананда

Избежание shufне упоминается в вопросе. Этот ответ по-прежнему будет полезен для других пользователей.
Scai

0

Онлайнер, использующий только Zsh:

files=(*); for x in {1..30}; do i=$((RANDOM % ${#files[@]} + 1)); echo "${files[i]}"; done

То же самое в Bash, где индексы массива начинаются с нуля:

files=(*); for x in {1..30}; do i=$((RANDOM % ${#files[@]})); echo "${files[i]}"; done

Обратите внимание, что ни одна из версий не учитывает дубликаты.


1
Это может перечислить один и тот же файл более одного раза. Избежать этого - значительная часть проблемы.
Жиль "ТАК - перестань быть злым"

Жиль: совершенно верно, поэтому я сказал: «Обратите внимание, что ни одна из версий не учитывает дубликаты». Вы все еще можете сделать это в чистом Bash, если вам не нужны временные сложности и перестраивать массив каждый раз, когда вы удаляете из него случайный. Даже близко не к одной строчке, но, конечно, это не было требованием.
Янмезен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.