Wyświetl X losowych plików z katalogu

14

Czy istnieje sposób wyświetlenia listy powiedzmy 30 losowych plików z katalogu przy użyciu standardowych poleceń systemu Linux? (w zsh)

Najlepsza odpowiedź opisana tutaj nie działa dla mnie ( sortnie rozpoznaje opcji -R)

Amelio Vazquez-Reina
źródło
jestem ciekawy, na jakim systemie operacyjnym jesteś.
ixtmixilix

Odpowiedzi:

7

Ponieważ wspominasz o zsh:

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

Możesz zamienić na printsay ogg123i na *say**/*.ogg

Stéphane Chazelas
źródło
19

Spróbuj przesłać dane lswyjściowe do shuf, np

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

-nFlaga określa ile losowe pliki, które chcesz.

Renan
źródło
command not found(nie zainstalowany): /
Amelio Vazquez-Reina,
Dziwne ... powinno być częścią coreutils. Jeśli twoje coreutils są stare, wtedy polecenia nie będzie.
Renan
6
Jest to szybki i brudny sposób, również bym go użył - do jednorazowego skryptu. Aby uzyskać coś bardziej trwałego, unikaj analizowania wynikówls .
janmoesen
@janmoesen Nie wiedziałem o tym. Dzięki!
Renan
@Renan Nie każdy Unix ma domyślnie zainstalowane jądra GNU.
Kusalananda
2

Łatwo to rozwiązać za pomocą odrobiny Perla. Wybierz cztery pliki losowo z bieżącego katalogu:

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

Jednak do użytku produkcyjnego wybrałbym rozszerzony skrypt, który nie opiera się na lsdanych wyjściowych, może zaakceptować dowolny katalog, sprawdza twoje argumenty itp. Zauważ, że sam losowy wybór to wciąż tylko kilka wierszy.

#!/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";
}
ire_and_curses
źródło
Imho skrypt Perla nie jest „standardowym poleceniem unixowym”. Problem ten można łatwo rozwiązać w dowolnym języku skryptowym wysokiego poziomu, takim jak Perl, Python lub Ruby, ale bardziej interesujący, jeśli jest bezpośrednio w wierszu poleceń.
gerrit
1
@gerrit - Rozumiem. Podałem to, ponieważ preferowana odpowiedź (użycie shuf) nie była wystarczająca dla PO. Co do tego, co jest i nie jest standardem Unix - Perl istnieje wszędzie i rozwiązuje problem zwięźle i solidnie. Gdybym podał to jako linijkę Perla, czy liczyłoby się to jako „linia poleceń”? Czy fakt, że Perl jest potężny, naprawdę jest argumentem przeciwko istnieniu tej odpowiedzi?
ire_and_curses
Powiedziałbym, że to odpowiedź na inne pytanie. Oczywiście w każdym w pełni funkcjonalnym języku programowania ten problem jest trywialny, dla mnie interesującą częścią pytania jest to, czy można to zrobić / bez / uciekając się do skryptu ~ 20 LOC; języki skryptowe są potężne, ale nie sądzę, aby Perl klasyfikował jako polecenie (takie jak OP wymagało; i nie, jeśli podasz 200-znakowy wiersz poleceń wzywający Perla, miałbym taką samą opinię).
gerrit
@gerrit - Być może mogę być jaśniejszy. Spójrz na moją edycję: perl -MList::Util=shuffle -e 'print shuffle(ls )' | head -n 4Czy to bardziej to, czego szukałeś?
ire_and_curses
Tak, usunąłem moją opinię, która była wprawdzie nieco trudna.
gerrit
1

Proste rozwiązanie, które pozwala uniknąć parsowania ls, a także działa ze spacjami:

shuf -en 30 dir/* | while read file; do
    echo $file
done
scai
źródło
Jak widać w innych komentarzach, OP działa na systemie bez shuf.
Kusalananda
Unikanie shufnie jest wspomniane w pytaniu. Ta odpowiedź będzie nadal pomocna dla innych użytkowników.
scai
0

Oneliner wykorzystujący tylko Zsh:

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

To samo dotyczy Bash, gdzie indeksy tablicowe są zerowe:

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

Pamiętaj, że żadna wersja nie uwzględnia duplikatów.

janmoesen
źródło
1
Może to zawierać ten sam plik więcej niż jeden raz. Unikanie tego stanowi znaczną część problemu.
Gilles „SO- przestań być zły”
Gilles: całkiem słusznie, dlatego powiedziałem „Pamiętaj, że żadna wersja nie uwzględnia duplikatów”. Nadal możesz to zrobić w czystym Bashu, jeśli nie przejmujesz się złożonością czasu i przebuduj tablicę za każdym razem, gdy usuniesz z niej losową. Zatem nawet nie w pobliżu jednej linijki, ale oczywiście nie było to wymagane.
janmoesen