Daftar file acak X dari direktori


14

Apakah ada cara untuk membuat daftar katakanlah, 30 file acak dari direktori menggunakan perintah Linux standar? (dalam zsh)

Jawaban teratas yang dijelaskan di sini tidak berfungsi untuk saya ( sorttidak mengenali opsi -R)


Saya ingin tahu apa OS Anda.
ixtmixilix

Jawaban:


7

Karena Anda menyebutkan zsh:

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

Anda dapat mengganti printdengan mengatakan ogg123dan *dengan mengatakan**/*.ogg


19

Coba perpip lsoutput ke shuf, mis

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

The -nflag menentukan berapa banyak file acak yang Anda inginkan.


command not found(tidak terpasang): /
Amelio Vazquez-Reina

Aneh ... itu harus menjadi bagian dari coreutils. Jika coreutils Anda sudah tua, maka perintahnya tidak akan ada di sana.
Renan

6
Ini adalah cara cepat dan kotor, dan saya akan menggunakannya juga - untuk skrip satu kali. Untuk apa pun yang lebih tahan lama, hindari parsing outputls .
janmoesen

@janmoesen Saya tidak tahu tentang ini. Terima kasih!
Renan

@Renan Tidak setiap Unix memiliki GNU coreutils yang terinstal secara default.
Kusalananda

2

Sangat mudah untuk menyelesaikan ini dengan sedikit Perl. Pilih empat file secara acak dari direktori saat ini:

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

Untuk penggunaan produksi, saya akan menggunakan skrip diperluas yang tidak bergantung pada lsoutput, dapat menerima dir, memeriksa args Anda, dll. Perhatikan bahwa pemilihan acak itu sendiri masih hanya beberapa baris.

#!/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";
}

Saya seorang Perl-script bukan 'perintah standar unix'. Masalah ini mudah diselesaikan dalam bahasa scripting tingkat tinggi seperti Perl, Python atau Ruby, tetapi lebih menarik jika langsung di commandline.
gerrit

1
@gerrit - Saya mengerti maksud Anda. Saya memberikan ini karena jawaban yang disukai (menggunakan shuf) tidak cukup untuk OP. Seperti apa standar Unix dan Perl - ada di mana-mana, dan itu memecahkan masalah dengan ringkas dan kuat. Jika saya memberikan ini sebagai Perl one-liner, apakah itu akan dianggap sebagai 'command line'? Apakah fakta bahwa Perl sangat kuat merupakan argumen yang menentang keberadaan jawaban ini?
ire_and_curses

Saya akan mengatakan itu adalah jawaban untuk pertanyaan yang berbeda. Tentu saja dalam bahasa pemrograman yang berfitur lengkap, masalah ini sepele, bagi saya bagian yang menarik dari pertanyaan ini adalah apakah hal itu dapat dilakukan / tanpa / menggunakan skrip LOC ~ 20; bahasa scripting sangat kuat, tetapi saya tidak berpikir Perl mengklasifikasikan sebagai perintah (seperti yang diminta OP; dan tidak, jika Anda akan memberikan perintah 200-karakter dengan memanggil Perl, saya akan memiliki pendapat yang sama).
gerrit

@gerrit - Mungkin saya bisa lebih jelas. Lihatlah saya sunting: perl -MList::Util=shuffle -e 'print shuffle(ls )' | head -n 4Apakah ini lebih seperti apa yang Anda cari?
ire_and_curses

Ya, saya menghapus downvote saya yang memang agak keras.
gerrit

1

Solusi sederhana yang menghindari penguraian ls dan juga bekerja dengan spasi:

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

Seperti yang terlihat di komentar lain, OP ada di sistem tanpa shuf.
Kusalananda

Menghindari shuftidak disebutkan dalam pertanyaan. Jawaban ini masih akan bermanfaat bagi pengguna lain.
scai

0

Oneliner yang tidak menggunakan apa-apa selain Zsh:

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

Sama di Bash, di mana indeks array berbasis nol:

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

Perhatikan bahwa tidak ada versi yang mengambil duplikat ke akun.


1
Ini mungkin mendaftar file yang sama lebih dari sekali. Menghindari ini adalah bagian penting dari masalah.
Gilles 'SO- stop being evil'

Gilles: benar sekali, itulah sebabnya aku berkata, "Perhatikan bahwa tidak ada versi yang memperhitungkan duplikat." Anda masih bisa melakukannya di Bash murni, jika Anda tidak peduli dengan kompleksitas waktu dan membangun kembali array setiap kali Anda menghapus yang acak dari itu. Bahkan tidak dekat dengan one-liner, tapi tentu saja itu bukan keharusan.
janmoesen
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.