Desde que você mencionou o zsh:
rand() REPLY=$RANDOM
print -rl -- *(o+rand[1,30])
Você pode substituir print
com ogg123
e *
com **/*.ogg
Existe uma maneira de listar um conjunto de 30 arquivos aleatórios de um diretório usando comandos padrão do Linux? (em zsh
)
A principal resposta descrita aqui não funciona para mim ( sort
não reconhece a opção -R
)
Tente colocar a saída ls
em shuf
, por exemplo
$ touch 1 2 3 4 5 6 7 8 9 0
$ ls | shuf -n 5
5
9
0
8
1
O sinalizador -n
especifica quantos arquivos aleatórios você deseja.
É muito fácil resolver isso com um pouquinho de Perl. Selecione quatro arquivos aleatoriamente no diretório atual:
perl -MList::Util=shuffle -e 'print shuffle('ls')' | head -n 4
Para uso em produção, eu usaria um script expandido que não dependesse de ls
output, pudesse aceitar qualquer dir, verificasse seus args, etc. Observe que a própria seleção aleatória ainda é apenas um par de linhas .
#!/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";
}
Uma solução simples que evita a análise de ls e também funciona com espaços:
shuf -en 30 dir/* | while read file; do
echo $file
done
Um oneliner usando nada além de Zsh:
files=(*); for x in {1..30}; do i=$((RANDOM % ${#files[@]} + 1)); echo "${files[i]}"; done
O mesmo no Bash, onde os índices de array são baseados em zero:
files=(*); for x in {1..30}; do i=$((RANDOM % ${#files[@]})); echo "${files[i]}"; done
Note que nenhuma das versões leva em consideração duplicatas.