Wie benutzt man die ‘-prune’-Option von’ find ‘in sh?

Ich verstehe das Beispiel aus dem “Man find” nicht ganz, kann mir jemand Beispiele und Erklärungen geben? Kann ich regulären Ausdruck darin kombinieren?


Die detailliertere Frage ist wie folgt: schreibe ein Shell-Skript, changeall, das eine Schnittstelle wie “changeall [-r | -R]” string1 “” string2 “hat. Es findet alle Dateien mit dem Suffix .h, .C , .cc, oder .cpp und ändern Sie alle Vorkommen von “string1” in “string2”. -r ist die Option, nur im aktuellen Verzeichnis zu bleiben oder Unterverzeichnisse zu verwenden. HINWEIS: 1) für nicht rekursiven Fall ist ‘ls’ NICHT erlaubt , wir könnten nur ‘find’ und ‘sed’ verwenden. 2) Ich habe ‘find -depth’ versucht, aber es wurde NICHT unterstützt. Deshalb habe ich mich gefragt, ob ‘-prune’ helfen könnte, aber das Beispiel nicht verstanden ‘ Mann finde ‘.


EDIT2: Ich habe eine Aufgabe gemacht, ich habe keine Frage in großen Details gestellt, weil ich es gerne selbst beenden würde. Da ich es schon gemacht habe und es jetzt übergebe, kann ich jetzt die ganze Frage stellen. Außerdem habe ich es geschafft, den Auftrag ohne Verwendung von -prune zu beenden, würde es aber trotzdem gerne lernen.

   

Die Sache, die ich über -prune verwirrend fand, ist, dass es eine Aktion (wie -print ) ist, kein Test (wie -name ). Es ändert die To-Do-Liste, gibt aber immer True zurück .

Das allgemeine Muster für die Verwendung von -prune ist das:

 find [path] [conditions to prune] -prune -o \ [your usual conditions] [actions to perform] 

Sie wollen eigentlich immer das -o unmittelbar nach -prune , weil der erste Teil des Tests (bis hin zu -prune ) für das, was Sie eigentlich wollen, false (dh das Zeug, das Sie nicht beschneiden wollen) zurückgibt ).

Hier ist ein Beispiel:

 find . -name .snapshot -prune -o -name '*.foo' -print 

Dies findet die “* .foo” -Dateien, die nicht unter “.snapshot” -Verzeichnissen liegen. In diesem Beispiel ist -name .snapshot der “Test für -name .snapshot die Sie beschneiden möchten” und -name '*.foo' -print ist das “Zeug, das Sie normalerweise nach dem Pfad -name '*.foo' -print würden”.

Wichtige Hinweise :

  1. Wenn Sie nur die Ergebnisse drucken möchten, die Sie vielleicht gewohnt sind, lassen Sie die Aktion -print . Im Allgemeinen möchten Sie das nicht , wenn Sie -prune .

    Das Standardverhalten von find besteht darin, den gesamten Ausdruck mit der Aktion -print zu “and” zu -print wenn am Ende keine anderen Aktionen als -prune (ironisch) vorhanden sind. Das bedeutet, dass dies geschrieben wird:

     find . -name .snapshot -prune -o -name '*.foo' # DON'T DO THIS 

    entspricht dem Schreiben:

     find . \( -name .snapshot -prune -o -name '*.foo' \) -print # DON'T DO THIS 

    Das bedeutet, dass es auch den Namen des Verzeichnisses ausgibt, das Sie beschneiden, was normalerweise nicht Ihren Vorstellungen entspricht. Stattdessen ist es besser, die Aktion -print explizit anzugeben, wenn dies gewünscht ist:

     find . -name .snapshot -prune -o -name '*.foo' -print # DO THIS 
  2. Wenn Ihre “übliche Bedingung” zufällig mit Dateien übereinstimmt, die ebenfalls mit Ihrer Bereinigungsbedingung übereinstimmen, werden diese Dateien nicht in die Ausgabe einbezogen. Um das zu beheben, fügen Sie der Prune-Bedingung ein Prädikat vom -type d .

    Nehmen wir zum Beispiel an, wir wollten jedes Verzeichnis löschen, das mit .git gestartet wurde (das ist zugegebenermaßen etwas kompliziert – normalerweise muss man nur das Ding namens .git entfernen), aber außer dem wollte man alle Dateien sehen, einschließlich Dateien wie .gitignore . Du könntest das versuchen:

     find . -name '.git*' -prune -o -type f -print # DON'T DO THIS 

    Dies würde .gitignore in der Ausgabe nicht enthalten. Hier ist die feste Version:

     find . -type d -name '.git*' -prune -o -type f -print # DO THIS 

Zusätzlicher Tipp: Wenn Sie die GNU-Version von find , hat die Texinfo-Seite für find eine detailliertere Erklärung als ihre Manpage (wie für die meisten GNU-Utilities).

Beachten Sie, dass -prune nicht verhindert, in irgendein Verzeichnis abzusteigen, wie einige gesagt haben. Es verhindert das Absinken in Verzeichnisse, die dem Test entsprechen, auf den es angewendet wird. Vielleicht helfen einige Beispiele (siehe unten für ein Regex-Beispiel). Entschuldigung, dass es so lange dauert.

 $ find . -printf "%y %p\n" # print the file type the first time FYI d . f ./test d ./dir1 d ./dir1/test f ./dir1/test/file f ./dir1/test/test d ./dir1/scripts f ./dir1/scripts/myscript.pl f ./dir1/scripts/myscript.sh f ./dir1/scripts/myscript.py d ./dir2 d ./dir2/test f ./dir2/test/file f ./dir2/test/myscript.pl f ./dir2/test/myscript.sh $ find . -name test ./test ./dir1/test ./dir1/test/test ./dir2/test $ find . -prune . $ find . -name test -prune ./test ./dir1/test ./dir2/test $ find . -name test -prune -o -print . ./dir1 ./dir1/scripts ./dir1/scripts/myscript.pl ./dir1/scripts/myscript.sh ./dir1/scripts/myscript.py ./dir2 $ find . -regex ".*/my.*p.$" ./dir1/scripts/myscript.pl ./dir1/scripts/myscript.py ./dir2/test/myscript.pl $ find . -name test -prune -regex ".*/my.*p.$" (no results) $ find . -name test -prune -o -regex ".*/my.*p.$" ./test ./dir1/test ./dir1/scripts/myscript.pl ./dir1/scripts/myscript.py ./dir2/test $ find . -regex ".*/my.*p.$" -a -not -regex ".*test.*" ./dir1/scripts/myscript.pl ./dir1/scripts/myscript.py $ find . -not -regex ".*test.*" . ./dir1 ./dir1/scripts ./dir1/scripts/myscript.pl ./dir1/scripts/myscript.sh ./dir1/scripts/myscript.py ./dir2 

Normalerweise ist die native Art, wie wir Dinge in Linux tun und wie wir denken, von links nach rechts.
So würden Sie gehen und schreiben, was Sie zuerst suchen:

 find / -name "*.php" 

Dann drücken Sie wahrscheinlich Enter und erkennen, dass Sie zu viele Dateien aus Verzeichnissen erhalten, die Sie nicht möchten. Lassen Sie uns / media ausschließen, um die Suche nach Ihren gemounteten Laufwerken zu vermeiden.
Sie sollten jetzt einfach die folgenden an den vorherigen Befehl anhängen:

 -print -o -path '/media' -prune 

also ist der letzte Befehl:

 find / -name "*.php" -print -o -path '/media' -prune 

…………… | < --- Include ---> | ……………….. | < - -------- Ausschliessen ---------> |

Ich denke, diese Struktur ist viel einfacher und korreliert mit dem richtigen Ansatz

Hinzufügen zu den Ratschlägen, die in anderen Antworten gegeben wurden (ich habe keine Erfahrung, Antworten zu erstellen) …

Wenn Sie -prune mit anderen Ausdrücken kombinieren, gibt es einen feinen Unterschied im Verhalten, abhängig davon, welche anderen Ausdrücke verwendet werden.

@Laurence Gonsalves ‘Beispiel findet die “* .foo” -Dateien, die nicht unter “.snapshot” -Verzeichnissen liegen: –

 find . -name .snapshot -prune -o -name '*.foo' -print 

Dieser etwas andere Short-Hand wird jedoch möglicherweise versehentlich auch das .snapshot Verzeichnis (und alle verschachtelten .snapshot-Verzeichnisse) auflisten: –

 find . -name .snapshot -prune -o -name '*.foo' 

Der Grund ist (gemäß der Manpage auf meinem System): –

Wenn der angegebene Ausdruck keine der Primärzeichen -exec, -ls, -ok oder -print enthält, wird der angegebene Ausdruck effektiv ersetzt durch:

(gegebener_Ausdruck) -print

Das heißt, das zweite Beispiel entspricht dem Eingeben des folgenden, wodurch die Gruppierung von Termen geändert wird:

 find . \( -name .snapshot -prune -o -name '*.foo' \) -print 

Dies wurde zumindest unter Solaris 5.10 beobachtet. Ich benutze seit ca. 10 Jahren verschiedene Geschmacksrichtungen von * nix und habe erst kürzlich nach einem Grund gesucht, warum dies passiert.

Prune ist ein Recurse bei keinem Verzeichniswechsel.

Von der Manpage

Wenn -depth nicht gegeben ist, wahr; Wenn die Datei ein Verzeichnis ist, steigen Sie nicht in das Verzeichnis ein. Wenn -depth angegeben ist, false; Kein Effekt.

Grundsätzlich wird es in keine Unterverzeichnisse desendes.

Nimm dieses Beispiel:

Sie haben die folgenden Verzeichnisse

  • / home / test2
  • / home / test2 / test2

Wenn Sie find -name test2 :

Es wird beide Verzeichnisse zurückgeben

Wenn Sie find -name test2 -prune :

Es gibt nur / home / test2 zurück, da es nicht in / home / test2 nach / home / test2 / test2 absteigt

Ich bin kein Experte (und diese Seite war sehr hilfreich zusammen mit http://mywiki.wooledge.org/UsingFind )

Gerade bemerkt -path ist für einen Pfad, der vollständig mit dem String / Pfad übereinstimmt, der direkt nach find (in diesen Beispielen), wobei as -name mit allen -name übereinstimmt.

 find . -path ./.git -prune -o -name file -print 

Blockiert das .git-Verzeichnis in Ihrem aktuellen Verzeichnis ( wie Sie es gefunden haben . )

 find . -name .git -prune -o -name file -print 

Blockiert alle .git-Unterverzeichnisse rekursiv.

Beachten Sie, dass die ./ extrem wichtig ist !! -path muss mit einem Pfad übereinstimmen, der mit verankert ist . oder was auch immer kommt, nachdem du herausgefunden hast, ob du Streichhölzer bekommst (von der anderen Seite des oder ‘ -o ‘), wird dort wahrscheinlich nicht beschnitten! Ich war mir naiv dessen nicht bewusst und es brachte mich dazu, -path zu verwenden, wenn es großartig ist, wenn Sie nicht alle Unterverzeichnisse mit demselben Basisnamen beschneiden wollen: D

Zeige alles inklusive dir selbst, aber nicht seine langweiligen Inhalte:

 find . -print -name dir -prune 

Wenn Sie alle guten Antworten hier lesen, ist mein Verständnis jetzt, dass die folgenden alle die gleichen Ergebnisse liefern:

 find . -path ./dir1\* -prune -o -print find . -path ./dir1 -prune -o -print find . -path ./dir1\* -o -print #look no prune at all! 

Aber der letzte wird viel länger dauern, da er immer noch alles in Dir1 sucht. Ich denke, die wahre Frage ist, wie man unerwünschte Ergebnisse herausfiltert -or herausfiltert, ohne sie tatsächlich zu suchen.

Also denke ich, dass “Pflaume” bedeutet, dass du keine anständigen vergangenen Matches hast, sondern dass du es als erledigt ansiehst …

http://www.gnu.org/software/findutils/manual/html_mono/find.html “Dies ist jedoch nicht wegen der Wirkung der ‘-prune’ Aktion (die nur verhindert, dass weitere Abstieg, es nicht sicher ist Wir ignorieren diesen Eintrag.) Dieser Effekt ist stattdessen auf die Verwendung von “-o” zurückzuführen. Da die linke Seite der Bedingung “oder” für ./src/emacs erfolgreich war, ist es nicht erforderlich, Hand-Seite (‘-print’) überhaupt für diese bestimmte Datei. ”