Список 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 старий, команда не буде там.
Ренан

6
Це швидкий і брудний спосіб, і я б його також використав - для одноразового сценарію. Що-небудь більш довговічне, уникайте аналізу результатівls .
janmoesen

@janmoesen Я про це не знав. Спасибі!
Ренан

@Renan Не кожен Unix за замовчуванням встановлений GNU coreutils.
Kusalananda

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, але ще цікавіше, якщо вона безпосередньо знаходиться в командному рядку.
Герріт

1
@gerrit - я розумію. Я забезпечив це тим, що бажана відповідь (використання shuf) була недостатньою для ОП. Що стосується того, що є, а що не є стандартом Unix - Perl існує скрізь, і це вирішує проблему лаконічно і надійно. Якби я дав це як однолінійний Perl, чи вважали б це "командним рядком"? Чи справді Perl є потужним аргументом проти існування цієї відповіді?
ire_and_curses

Я б сказав, що це відповідь на інше питання. Звичайно, в будь-якій повнофункціональній мові програмування ця проблема є тривіальною, для мене цікава частина питання полягає в тому, чи можна це зробити / без / вдатися до сценарію ~ 20 LOC; мови сценаріїв є потужними, але я не думаю, що Perl класифікується як команда (як, наприклад, ОП просив; і ні, якби ви дали командний рядок на 200 символів, що викликає Perl, я мав би таку ж думку).
Герріт

@gerrit - Можливо, я можу бути зрозумілішим. Погляньте на мою редакцію: perl -MList::Util=shuffle -e 'print shuffle(ls )' | head -n 4Це більше схоже на те, що ви шукали?
ire_and_curses

Так, я зняв свій потвор, який, правда, був трохи суворим.
Герріт

1

Просте рішення, яке дозволяє уникнути розбору ls, а також працює з пробілами:

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

Як видно з інших коментарів, ОП працює в системі без shuf.
Kusalananda

Уникання 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, якщо вам не байдуже складність часу та перебудовувати масив кожного разу, коли ви видаляєте з нього випадковий. Тоді навіть близько до одноводкового, але, звичайно, це не було вимогою.
janmoesen
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.