Ist es möglich, ein 'find -exec' in ein anderes 'find -exec' zu schachteln?

14

Etwas wie das Folgende ist das, wonach ich suche, aber mein Code funktioniert nicht, egal wie ich flüchte {}und+ ;

find ./ -maxdepth 1 -type d -name '.*' -exec \
    find {} -maxdepth 1 -type f -name '*.ini' -exec \
        md5sum \{\} \\; \;

Nach diesen sehen Unix - & - Linux Frage fand ich , dass der folgende Code funktioniert, aber es ist nicht Verschachtelung Fund als solche, und ich vermute , dass es einen besseren Weg, diese besondere Arbeit zu tun.

find ./ -maxdepth 1 -type d -name '.*' \
-exec bash -c 'for x; do
    find "$x" -maxdepth 1 -type f -name "*.ini" \
    -exec md5sum \{\} \;; \
done' _ {} \+

Gibt es eine Möglichkeit zum Verschachteln, find -execohne dass eine Shell (wie oben) mit all ihren verrückten Zitier- und Fluchtbeschränkungen aufgerufen werden muss?

Oder kann dies direkt in einem einzelnen Suchbefehl unter Verwendung einer Mischung seiner vielen Parameter erfolgen?

Peter.O
quelle
4
Es ist zwar möglich, das zu tun, wonach Sie fragen, aber wenn die Dinge so komplex werden, wechsle ich zu Shell- oder Perl-Skripten. Ihr zweites Code-Snippet tut dies so ziemlich nur mit dem Shell-Skript inline. Heroische Einzeiler sind unterhaltsam, aber schwer zu verstehen und daher schwer zu pflegen. Es sei denn, dies ist ein One-Shot-Deal, in dem Sie sich dennoch irgendwie auskennen. Ich sehe keinen guten Grund, es anders als die intellektuelle Herausforderung zu tun.
Warren Young
1
@Warren Young: Ich glaube nicht, dass das Konzept komplex ist, aber ich nehme an, dass es keine einfache Möglichkeit gibt, damit umzugehen. findWenn finddies nicht möglich ist, warum wird findes dann als Werkzeug so verehrt (?)? zum Finden von Dateien zu verwenden? ... Ich habe später festgestellt, dass dies find ./ -maxdepth 2 -path '.*/*.ini' -type f -exec md5sum {} \+in meiner Situation gut funktioniert (der Verweis auf jw013 hat -prunemich auf der Manpage dazu geführt), aber ich frage mich, ob es eine robuste Methode ist (in Gattungen). Ich habe find(in weniger als einem Jahr Linux) noch nie so locateviel benutzt, wie ich brauchte, also ist es Neuland.
Peter.O
1
Der -pathTest ist genau das, was ich vorschlagen wollte. Damit solltest du in der Lage sein, alles zu tun , was du willst (Entschuldigung für den Verein Ace Of Base;))
rozcietrzewiacz

Antworten:

8

Ich würde versuchen, einen einzigen Fund wie:

find .*/ -maxdepth 1 -type f -name '*.ini' -execdir md5sum {} +

oder sogar (gar nicht find, nur Shell-Globbing)

md5sum .*/*.ini

Obwohl dies die -type fPrüfung fehlt , funktioniert dies nur, wenn Sie keine Verzeichnisse / Nicht-Dateien haben, die auf enden .ini. Wenn Sie das tun, könnten Sie verwenden

for x in .*/*.ini; do 
    if [ -f "$x" ]; then 
        md5sum "$x"
    fi
done

Dies würde jedoch den Vorteil verlieren, nur einen md5sum-Aufruf zu benötigen.

Bearbeiten

Für eine allgemeine und sichere Verkettungsmethode findkönnen Sie so etwas tun

find <paths> <args> -print0 | xargs -0 -I{.} find {.} <args for second find> [etc.]
jw013
quelle
Ich erhalte einen Fehler mit dem -f(f?) Und dann einen weiteren Fehler mit -execdir.. Wenn ich -execdir durch -exec ersetze und / oder auch md5sum durch print ersetze, erhalte ich nichts ..
Peter.O
Danke, für die Alternative ... aber ich bin mehr auf der findSuche nach einer Möglichkeit, dies zu tun ... Es ist nicht so sehr, dass ich nur dieses Beispiel auflösen möchte, ich suche nach Einsichten in die Wege von find-fu ... Vielleicht ist mehr Flaum als FU in der Entdeckung (ich weiß es nicht, weil ich es so gut wie nie benutzt habe), und dies ist die erste Situation, die ich wirklich wollte (eigentlich für Bilddateien) und die -exec Feature, von dem ich so viel gehört habe, scheint nicht so mächtig zu sein, wie es rep (?) andeutet ... (+1 für die Alternativen) .. aber dein findBeispiel funktioniert einfach nicht (immer noch) )
Peter.O
Ich erhalte diesen Fehler für den findBefehl: ... find: The relative path ~ / bin 'ist in der Umgebungsvariablen PATH enthalten, die in Kombination mit der Aktion -execdir von find unsicher ist. Bitte entferne diesen Eintrag aus $ PATH` .... Vielleicht wird es also funktionieren, aber ich muss sagen, dass ich schon seit einiger Zeit versuche, das ~ / bin loszuwerden ... Ich muss so viel mehr nehmen ernsthafter Blick darauf ... Ich weiß nicht, wo ich es eingestellt habe ... irgendwelche Ideen, wo es lauern könnte; das ~/binin meinem
PFAD
Ich denke, die Kraft von findwird am besten in Situationen gewürdigt, die nicht vollständig mit Globs erreicht werden können, aber da solche Situationen selten sind, brauche ich normalerweise nicht viel zu finden.
jw013
Okay .. das ist ein interessanter und guter Punkt (über die Verwendung von Globs) ...
Peter.O
2

Ihr ursprüngliches Problem erfordert keinen rekursiven Aufruf von find, aber ich nehme an, das war nicht der Punkt.

Ich glaube, es ist nicht möglich, find rekursiv so aufzurufen, wie Sie es möchten.

Der folgende Befehl ruft find nicht rekursiv auf (oder verschachtelt, wie auch immer er genannt wird), aber können Sie nicht einfach eine Ergebnismenge der ersten Suche nehmen und an die zweite weiterleiten? So würde ich instinktiv vorgehen:

find `find ./ -maxdepth 1 -type d -name '.*'` \
    -maxdepth 1 -type f -name '*.ini' -exec md5sum {} \;

Sie können es auch xargszum Ausführen des zweiten Suchvorgangs verwenden.

Aktualisieren:

Ich wollte hinzufügen, dass, da die meisten UNIX-Dienstprogramme anstelle von einem mehrere Dateinamenargumente verwenden, Sie in der Regel Folgendes vermeiden -execkönnen:

md5sum `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`

Beim Verschachteln von Backticks fügen Sie einfach Backslashes \vor den inneren hinzu.

Wenn wir uns vorstellen, dass md5sumnur ein Dateinamenargument verwendet wird, können wir es immer in eine forSchleife einschließen:

for f in `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`
do
    md5sum $f
done

Beachten Sie, dass dies schwieriger wird, wenn Datei- / Verzeichnisnamen -betroffen sind, die mit einem Leerzeichen beginnen oder ein Leerzeichen enthalten. UNIX-Dienstprogramme spielen nicht gut mit ihnen. In diesem Fall ./müssen --Anführungszeichen oder Anführungszeichen hinzugefügt werden .

Offensichtlich ist das ursprüngliche Beispiel nicht gut, weil wir einfach tun könnten:

md5sum .*/*.ini
schnappen
quelle
1
Sie haben einen guten Überblick über die Situation gegeben, aber alle gezeigten findMethoden erhalten eine Fehlermeldung, wenn eine Datei / ein Verzeichnis Leerzeichen enthält ... Das md5sum .*/*.inifunktioniert gut ... Ich bekomme allmählich das allgemeine Gefühl, dass * Warren Youngs * Kommentar über Dinge, die 'komplex' werden, findgeschieht zu Beginn des Spiels :), aber ich findgehe davon aus, dass sie sich auszahlen, wenn die Bedingungstests komplizierter sind. wie es scheint, gibt es einfachere Möglichkeiten, um es zu tun .. (aber Perl ist nicht "einfach" für mich (noch) ...
Peter.O
0

Zumindest habe ich es geschafft, 2 find-Befehle zu verschachteln:

find ~ -maxdepth 1 -type d -name '.*' -execdir \
    find {} -maxdepth 1 -type f -name '*.ini' \;

Aber ich habe nicht gelöst, um einen anderen -exec (dir) - Anruf von dort aufzurufen.

Benutzer unbekannt
quelle
Ja, das ist genau mein Problem :)
Peter.O
Ja, aber nicht verschachteln 3 ist nicht dasselbe wie nicht verschachteln 2. :)
Benutzer unbekannt