Ich versuche, mit dem find
Befehl die Größe einer bestimmten Gruppe von Dateien aufzulisten, erhalte aber keine Ausgabe. Der von mir verwendete Befehl lautet:
find POD -type f -name *.mp3 -or -name *.ogg -ls
Das erzeugt keine Ausgabe. Während:
find POD -type f -name *.mp3 -or -name *.ogg
erzeugt eine Ausgabe, ich habe auch die folgenden Aktionen ausprobiert:
-printf "%p %k KB\n"
-exec ls -ls '{}' \;
-print0
aber alle diese Aktionen geben keine Ausgabe aus. Wenn ich eine dieser Aktionen mit einem anderen Ausdruck verwende, z. B.:
find . -maxdepth 1 -type f -printf "%p %k KB\n"
Ich bekomme auch die erwartete Ausgabe. Hat jemand eine Idee, wo das Problem liegt? Ich verwende:
Linux irimi 3.10.37-1-MANJARO #1 SMP Mon Apr 14 20:56:29 UTC 2014 x86_64 GNU/Linux
auch bekannt als eine aktuelle Manjaro-Linux-Distribution. Die Shell, die ich verwende, ist: /bin/bash
Version 4.3.8(1)-release
.
Der Inhalt meiner SHELLOPTS
Umgebungsvariable ist:
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
meine BASHOPTS
Umgebungsvariable ist:
cdspell:checkwinsize:cmdhist:complete_fullquote:dotglob:expand_aliases:extglob:extquote:force_fignore:histappend:hostcomplete:interactive_comments:nocaseglob:progcomp:promptvars:sourcepath
Auch hier wäre ich für jede Hilfe beim Debuggen sehr dankbar.
Antwort1
Es gibt eine Falle mit demund/oderSchlüsselwörter auf find
. or
werden auf alle folgenden Parameter angewendet, einschließlich der Aktion ( -ls
in Ihrem Beispiel). and
Ausdrücke ohne or
(oder mit and
) werden in Lesereihenfolge ausgewertet, mit einem letzten Stopp als „false“. Es gibt kein implicit ()
.
Der Befehl find POD -type f -name *.mp3 -or -name *.ogg -ls
bedeutet also:
- Suche (ausgehend vom POD-Verzeichnis) nach Dateien --- wenn keine Datei gefunden: STOP
- sonst (Datei gefunden) Musterübereinstimmung prüfen
*.mp3
--- wenn Musterübereinstimmung: STOP ! (weilOR
ab hier angewendet und nur, wenn der vorherige Befehl fehlgeschlagen ist (aber nur der vorherige Befehl, nicht die vorherigen Befehlsgruppen)
und weil Sie in der Befehlszeile eine Execute-Anweisung (,, ....) hinzufügen, gibt es keinen impliziten Befehl -ls
und daher nichts auszuführen, wenn 1) alle Bedingungen von 1) erfüllt sind (Datei und Muster übereinstimmen). Wenn Sie das Letzte entfernen, gibt es am Ende jeder Bedingung eine implizite Verzweigung.-exec
-print
-print
-ls
-print
- andernfalls, wenn das Muster nicht übereinstimmt, nach allem (Datei/Verzeichnis) suchen, das dem Muster entspricht,
*.ogg
und es auflisten (das-ls
ist kein Bedingungsbefehl, er wird nur ausgeführt, wenn der vorherige Befehl/Test „Muster“*.ogg
wahr ist). Aber wegen 1), 2) wird nur für NICHT-MP3-Dateien ausgewertet. Wenn Sie keine.ogg
Dateien haben, sehen Sie nichts.
Lösung 1 Wiederholen Sie den Ausführungsbefehl in jedem logischen Zweig
find POD -type f -name "*.mp3" -ls -or -name "*.ogg" -ls
Lösung 2(Shell-geschützte) Klammer hinzufügen
find POD -type f \( -name "*.mp3" -ls -or -name "*.ogg" \) -ls
Notiz Sie sollten die Muster schützen, um eine Shell-Musterauswertung im aktuellen Verzeichnis zu vermeiden.
Antwort2
Ich denke, es liegt an der Auswertungsreihenfolge (Fehlen einer expliziten Priorität), z. B. wenn
-name '*.mp3' -o -name '*.ogg' -ls
Wenn dann -name '*.ogg'
„false“ ausgewertet wird, ls
wird die Aktion nicht ausgeführt. Sie können das erwartete Verhalten erzielen, indem Sie Ihre OR-Ausdrücke in Klammern gruppieren – zum Beispiel, wenn
$ ls tests
file1.mp3 file2.mp3 file3.mp3
Dann
$ find tests \( -name '*.mp3' -o -name '*.ogg' \) -print
tests/file3.mp3
tests/file1.mp3
tests/file2.mp3
wohingegen
$ find tests -name '*.mp3' -o -name '*.ogg' -print
erzeugt keine Ausgabe. Beachten Sie, dass
$ find tests -name '*.mp3' -o -name '*.ogg'
ist ein Sonderfall, da er implizit behandelt wird als
$ find tests \( -name '*.mp3' -o -name '*.ogg' \) -print
Beachten Sie auch, dass es empfehlenswert ist, Shell-Globs in einem find
Befehl in Anführungszeichen zu setzen oder zu maskieren, um zu verhindern, dass die Shell sie erweitert – siehe den NON-BUGS
Abschnitt auf der Manpage „Find“.