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)


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


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.


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";
}

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

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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.