Ich versuche, mit Bash „find“ alle Ordner zu verarbeiten, die eine .log-Datei enthalten, und ihre Größe zu ermitteln. Das Platzhalterzeichen funktioniert jedoch nicht wie erwartet. Dies gibt nichts zurück:
find . -type d -exec test -e '{}/*.log' \; -exec du -d0 '{}' \;
Wenn ich es jedoch *.log
durch ersetze foo.log
, funktioniert es wie erwartet für Verzeichnisse, die diesen Dateinamen enthalten.
Basierend auf einigen ähnlichen SE-Beiträgen habe ich Folgendes versucht:
find . -type d -exec bash -c 'test -e "{}/*.log"' \; -exec du -d0 '{}' \;
find . -type d -exec bash -c 'test -e "$1/*.log"' '{}' \; -exec du -d0 '{}' \;
aber die funktionieren nicht besser.
Antwort1
Mit find … -exec test -e '{}/*.log'
übergeben Sie eine Zeichenfolge wie something/*.log
an test
, wobei *
istwörtlich. Keines der Tools behandelt es als Platzhalter. Einige Implementierungen von find
werden nicht einmal erweitert, {}
wenn es Teil eines Arguments ist (im Gegensatz zu {}
einem vollständigen Argument).
Einer Ihrer späteren Versuche wird {}
in den Shellcode eingebettet.Niemals {}
in den Shell-Code einbetten. Der andere Versuch ist in dieser Angelegenheit besser, Sie sind einer Lösung nahe. Dies wirdirgendwiearbeiten:
# still flawed though
find . -type d -exec bash -c 'test -e "$1/"*.log' bash '{}' \; -exec du -d0 '{}' \;
SehenWas ist das zweite sh in sh -c 'some shell code' sh
?. Die wichtigste „Lösung“ besteht jedoch darin, das Asterisk im Shell-Code nicht in Anführungszeichen zu setzen. Auf diese Weise ist es ein Platzhalter in der inneren Shell (aber nicht in der äußeren Shell, da steht es richtig in einfachen Anführungszeichen). Das Problem ist, dass es *.log
sich auf mehr als ein Wort ausdehnen kann (wenn es viele übereinstimmende Dateien gibt) und in diesem Fall wird der Aufruf abgebrochen test
.
Der folgende Code findet Verzeichnisse mit *.log
Dateien:
find . -type d -exec sh -c '
for f in "$1/"*.log; do test -e "$f" && exit 0; done; exit 1
' sh {} \; -print
Der Code ist portierbar. Es besteht kein Bedarf für inner bash
, sh
sollte schneller sein. Ersetzen Sie es bei Bedarf -print
durch .-exec du …
Dies funktioniert, indem exit 0
die innere Shell success ( ) zurückgibt, sobald test
die Existenz einer passenden Datei¹ bestätigt wurde. Noch nicht getestete passende Dateien (falls vorhanden) werden nicht vergeblich getestet, das spart Zeit. Wenn es keine Übereinstimmung gibt, bleibt das Muster wörtlich, test
schlägt fehl und die gesamte Shell wird mit failure ( exit 1
) beendet. Denken Sie daran -exec
, dass es sich auch um einen Test handelt, es beeinflusst also, ob -print
(oder -exec du …
oder was auch immer Sie dort eingeben) ausgeführt wird.
Ein anderer Ansatz könnte darin bestehen, find
sich selbst passende Dateien suchen zu lassen mit
find . -name '*.log' … -print
und um dessen Ausgabe zu analysieren, um Verzeichnisnamen zu isolieren, und schließlich xargs
mit zu verwenden du
. Verzeichnisse könnten mehrfach vorkommen, Zeilenumbrüche in Pfadnamen würden nicht portablen Code erfordern (beginnend mit -print0
). Ich denke, das wäre unnötig kompliziert. Das Suchen von Verzeichnissen scheint besser.
¹ Hinweis test -e
: Gibt es eine Dateidas kann ein Verzeichnis oder was auch immer sein. Um das Vorhandensein einer regulären Datei zu bestätigen, verwenden Sie test -f
.
Antwort2
Es wäre einfacher, Protokolldateien zu finden/zu scannen und dann die eindeutigen Verzeichnisnamen zu erfassen.
Dieser find
Befehl sollte die Verzeichnisse herausziehen und uniq
Duplikate entfernen. Die -z
/ -0
-Flags helfen dabei, sicherzustellen, dass Pfadnamen mit Zeilenumbrüchen/Leerzeichen/Anführungszeichen fehlerfrei analysiert werden:
find . -type f -name \*.log -exec dirname -z {} \+ | uniq -z | xargs -0 -r du -d0
Fügen Sie es hinzu | sort -rn |head
, wenn Sie nach der größten Datenträgernutzung suchen.