Listet X zufällige Dateien aus einem Verzeichnis auf

14

Gibt es eine Möglichkeit, 30 zufällige Dateien aus einem Verzeichnis mit Standard-Linux-Befehlen aufzulisten? (in zsh)

Die hier beschriebene Top-Antwort funktioniert bei mir sortnicht (erkennt die Option nicht -R)

Amelio Vazquez-Reina
quelle
Ich bin gespannt, auf welchem ​​Betriebssystem du bist.
ixtmixilix

Antworten:

7

Da Sie zsh erwähnen:

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

Sie können printmit sagen ogg123und *mit sagen ersetzen**/*.ogg

Stéphane Chazelas
quelle
19

Versuchen Sie, den lsAusgang zu leiten shuf, z

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

Das -nFlag gibt an, wie viele zufällige Dateien Sie möchten.

Renan
quelle
command not found(nicht installiert): /
Amelio Vazquez-Reina
Seltsam ... es sollte ein Teil von Coreutils sein. Wenn Ihre coreutils alt sind, ist der Befehl nicht da.
Renan,
6
Dies ist der schnelle und schmutzige Weg, und ich würde ihn auch verwenden - für ein einmaliges Skript. Für etwas mehr haltbar, Parsen vermeiden die Ausgabels .
Januar
@janmoesen Ich wusste nichts davon. Vielen Dank!
Renan
@Renan Nicht auf jedem Unix sind standardmäßig GNU-Coreutils installiert.
Kusalananda
2

Mit ein bisschen Perl ist das ganz einfach zu lösen. Wählen Sie vier zufällige Dateien aus dem aktuellen Verzeichnis aus:

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

Für die Produktion würde ich jedoch ein erweitertes Skript verwenden, das sich nicht auf die lsAusgabe stützt, ein beliebiges Verzeichnis akzeptiert, Ihre Argumente überprüft usw. Beachten Sie, dass die Zufallsauswahl selbst immer noch nur ein paar Zeilen umfasst.

#!/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
quelle
Imho ein Perl-Skript ist kein "Standard-Unix-Befehl". Dieses Problem ist in jeder höheren Skriptsprache wie Perl, Python oder Ruby leicht zu lösen, aber interessanter, wenn es direkt in der Befehlszeile angezeigt wird.
Gerrit
1
@ Gerrit - ich nehme Ihren Punkt. Ich habe dies angegeben, weil die bevorzugte Antwort (mit shuf) für das OP nicht ausreichend war. Was ist und was nicht Standard Unix - Perl gibt es überall und es löst das Problem kurz und bündig. Wenn ich dies als Perl-Einzeiler angegeben hätte, hätte das als "Befehlszeile" gezählt? Ist die Tatsache, dass Perl mächtig ist, wirklich ein Argument gegen die Existenz dieser Antwort?
ire_and_curses
Ich würde sagen, es ist eine Antwort auf eine andere Frage. Natürlich ist dieses Problem in jeder voll ausgestatteten Programmiersprache trivial, für mich ist der interessante Teil der Frage, ob es getan werden kann / ohne / auf ein ~ 20 LOC-Skript zurückzugreifen; Skriptsprachen sind mächtig, aber ich glaube nicht, dass Perl als Befehl klassifiziert wird (wie es das OP verlangt hat; und nein, wenn Sie eine 200-stellige Befehlszeile angegeben hätten, die Perl aufruft, hätte ich die gleiche Meinung gehabt).
Gerrit
@ Gerrit - Vielleicht kann ich klarer sein. Schauen Sie sich meine Bearbeitung an: perl -MList::Util=shuffle -e 'print shuffle(ls )' | head -n 4Ist das eher das, was Sie gesucht haben?
ire_and_curses
Ja, ich habe mein Downvote entfernt, was zugegebenermaßen ein bisschen hart war.
Gerrit
1

Eine einfache Lösung, die das Parsen von ls vermeidet und auch mit Leerzeichen arbeitet:

shuf -en 30 dir/* | while read file; do
    echo $file
done
scai
quelle
Wie in anderen Kommentaren zu sehen ist, befindet sich das OP auf einem System ohne shuf.
Kusalananda
Vermeiden shufwird in der Frage nicht erwähnt. Diese Antwort ist für andere Benutzer weiterhin hilfreich.
scai
0

Ein Oneliner, der nur Zsh verwendet:

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

Dasselbe gilt für Bash, wo Array-Indizes auf Null basieren:

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

Beachten Sie, dass keine der Versionen Duplikate berücksichtigt.

janmoesen
quelle
1
Dies kann dieselbe Datei mehrmals auflisten. Dies zu vermeiden, ist ein wesentlicher Teil des Problems.
Gilles 'SO- hör auf böse zu sein'
Gilles: Ganz richtig, deshalb habe ich gesagt: "Beachten Sie, dass keine der Versionen Duplikate berücksichtigt." Sie können dies immer noch in Bash tun, wenn Sie sich nicht um die Komplexität der Zeit kümmern und das Array jedes Mal neu erstellen, wenn Sie ein zufälliges Array daraus entfernen. Also nicht einmal in der Nähe eines Einliners, aber das war natürlich keine Voraussetzung.
Januar