
Ich möchte eine zufällig ausgewählte Datei über das Terminal öffnen. Ich habe gefunden shuf
, was genau das Dienstprogramm zu sein scheint, das ich brauche, obwohl ich nicht weiß, wie ich den Befehl, mit dem ich arbeite, rekursiv machen kann.
Anfangs habe ich verwendet open $(ls | gshuf -n1)
, was gut funktioniert, wenn ich eine flache Verzeichnisstruktur habe. Wie kann ich dies in eine beliebige Anzahl von Unterverzeichnissen rekursiv machen und Dateien wie .DS_Store
und Ordner herausfiltern?
Antwort1
- Nicht analysieren
ls
. - Richtig zitieren(es sei denn, Sie wissen, dass Ihre Shell dies behebt, z. B.
zsh
).
Das richtige Werkzeug ist find
. Es arbeitet rekursiv, das löst Ihr Hauptproblem. Sie können verschiedene Muster ausschließen, wenn Sie wissen wie.
Die grundlegende Verwendung sieht folgendermaßen aus:
open "$(find . -type f | shuf -n1)"
Zeilenumbrüche in Dateinamen unterbrechen dies. Ihre Tools unterstützen möglicherweise nicht-POSIX-Optionen, die die Übergabe von NUL-terminierten Daten ermöglichen, oder nicht. Dieser Codeausschnitt funktioniert in meinem Debian:
find . -type f -print0 | shuf -z -n1
Wenn Sie es jedoch in einbetten $(…)
, werden nachstehende Zeilenumbrüche (sofern vorhanden) trotzdem entfernt.
Um Namen auszuschließen, können Sie Syntax wie verwenden ! -name .DS_Store
, aber um ganze Unterverzeichnisse auszuschließen, benötigen Sie-prune
Es gibt Fallstricke:
- Die Reihenfolge der Operanden ist wichtig;
-prune
bei einem Verzeichnis sollte es beispielsweise vor stehen-type f
,-print
/-print0
gehört normalerweise ans Ende. - Logisches „oder“ (
-o
)erfordert oft Klammernund es ist nicht so intuitiv, wie Sie es sich vielleicht wünschen. - Das Weglassen von
-print
/ kann zu mehr Ergebnissen führen als Sie erwarten. Bei komplexer Logik ist es gut, /-print0
explizit einzuschließen .-print
-print0
Studieren Sie man 1 find
, um mehr zu erfahren. Dies ist ein funktionierendes Beispiel, das zwei Verzeichnisse und zwei Namensmuster ausschließt:
find . \( -name dir1 -o -name "dir 2" \) -prune -o -type f ! \( -name "*.txt" -o -name "echo*" \) -print
Da Sie $(…)
richtig zitieren müssen und ich Ihnen gesagt habe, dass Sie das tun sollen, sollten Sie wissen, dass die Anführungszeichen darin $(…)
separat analysiert werden. Dies hier ist beispielsweise richtig zitiert:
open "$(find . -type f ! -name "not this file" | shuf -n1)"
(vergleichendiese Antwort, Eigenart 2).