find -exec mit Platzhalter

find -exec mit Platzhalter

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 *.logdurch 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/*.logan test, wobei *istwörtlich. Keines der Tools behandelt es als Platzhalter. Einige Implementierungen von findwerden 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 *.logsich 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 *.logDateien:

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, shsollte schneller sein. Ersetzen Sie es bei Bedarf -printdurch .-exec du …

Dies funktioniert, indem exit 0die innere Shell success ( ) zurückgibt, sobald testdie 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, testschlä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, findsich selbst passende Dateien suchen zu lassen mit

find . -name '*.log' … -print

und um dessen Ausgabe zu analysieren, um Verzeichnisnamen zu isolieren, und schließlich xargsmit 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 findBefehl sollte die Verzeichnisse herausziehen und uniqDuplikate 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.

verwandte Informationen