Wie benutze ich die Option "-prune" in SH?
Frage
Ich verstehe das von der angegebene Beispiel nicht ganz man find
, Kann mir jemand ein paar Beispiele und Erklärungen geben? Kann ich einen regulären Ausdruck darin kombinieren?
Die detailliertere Frage ist wie folgt:
Schreiben Sie ein Shell -Skript, changeall
, was eine Schnittstelle hat wie changeall [-r|-R] "string1" "string2"
. Es wird alle Dateien mit einem Suffix von finden .h
, .C
, .cc
, oder .cpp
und alle Ereignisse von verändern string1
zu string2
. -r
ist Option, nur in aktuellem Dir zu bleiben oder Subdirs einzubeziehen.
HINWEIS:
- Für nicht rekursive Fall,
ls
ist nicht erlaubt, wir konnten nur verwendenfind
undsed
. - Ich habe es versucht
find -depth
Aber es wurde nicht unterstützt. Deshalb habe ich mich gefragt, ob-prune
könnte helfen, aber das Beispiel nicht verstanden vonman find
.
Edit2: Ich habe Auftrag gemacht, ich habe keine Frage in guten Details gestellt, weil ich sie selbst beenden möchte. Da ich es bereits getan habe und es eingreift, kann ich jetzt die ganze Frage angeben. Außerdem habe ich es geschafft, die Aufgabe zu beenden, ohne es zu verwenden -prune
, aber würde es trotzdem lernen.
Lösung
Das, worüber ich mich verwirrt habe -prune
ist, dass es eine Aktion ist (wie -print
), kein Test (wie -name
). Es verändert die "To-Do" -Liste, aber immer wahr zurückgibt.
Das allgemeine Muster für die Verwendung -prune
ist das:
find [path] [conditions to prune] -prune -o \
[your usual conditions] [actions to perform]
Du willst so ziemlich immer das -o
(logisch oder) unmittelbar danach -prune
, weil dieser erste Teil des Tests (bis hin zu und einschließlich -prune
) wird zurückkehren FALSCH Für das Zeug, das du tatsächlich willst (dh: das Zeug du dich nicht will ausgehen).
Hier ist ein Beispiel:
find . -name .snapshot -prune -o -name '*.foo' -print
Dies findet die "*.foo" -Dateien, die nicht unter ".snapshot" -Verzeichnungen sind. In diesem Beispiel, -name .snapshot
macht das [conditions to prune]
, und -name '*.foo' -print
ist [your usual conditions]
und [actions to perform]
.
Wichtige Notizen:
Wenn Sie nur die Ergebnisse ausdrucken möchten, werden Sie möglicherweise gewohnt, das auszulassen
-print
Aktion. Sie im Allgemeinen nicht will das tun, wenn du benutzst-prune
.Das Standardverhalten von Find ist zu "und" die gesamte Ausdruck mit dem
-print
Aktion, wenn es keine anderen Handlungen gibt als-prune
(Ironischerweise) am Ende. Das bedeutet, dass das schreibe:find . -name .snapshot -prune -o -name '*.foo' # DON'T DO THIS
entspricht dem Schreiben Folgendes:
find . \( -name .snapshot -prune -o -name '*.foo' \) -print # DON'T DO THIS
Das bedeutet, dass es auch den Namen des Verzeichnisses ausdrucken wird, das Sie beschneiden, was normalerweise nicht das ist, was Sie wollen. Stattdessen ist es besser, die explizit anzugeben
-print
Aktion, wenn Sie das wollen:find . -name .snapshot -prune -o -name '*.foo' -print # DO THIS
Wenn Ihre "übliche Bedingung" zu Dateien übereinstimmt, die auch zu Ihrer Pflaumenbedingung übereinstimmen nicht in die Ausgabe aufgenommen werden. Der Weg, dies zu beheben, besteht darin, a hinzuzufügen
-type d
Prädikat für Ihren Pflaumenzustand.Angenommen, wir wollten jedes Verzeichnis beschneiden, das mit dem begonnen hat
.git
(Dies ist zugegebenermaßen etwas erfunden - normalerweise müssen Sie nur das genannte Ding entfernen exakt.git
), aber ansonsten wollte alle Dateien, einschließlich Dateien wie.gitignore
. Sie könnten dies versuchen:find . -name '.git*' -prune -o -type f -print # DON'T DO THIS
Das würde nicht enthalten
.gitignore
im Ausgang. 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 verwenden find
, die Texinfo -Seite für find
hat eine detailliertere Erklärung als seine Manpage (wie für die meisten GNU -Dienstprogramme gilt).
Andere Tipps
Achten Sie darauf, dass -Prune nicht verhindert irgendein Verzeichnis, wie einige gesagt haben. Es verhindert, dass sich in Verzeichnisse, die dem Test entsprechen, auf den sie angewendet werden, einhergehen. Vielleicht helfen einige Beispiele (siehe unten für ein Regex -Beispiel). Entschuldigung dafür, dass dies so langwierig ist.
$ 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 machen wir die native Art und Weise, wie wir Dinge unter Linux machen und wie wir denken, von links nach rechts.
Sie würden also schreiben, was Sie zuerst suchen:
find / -name "*.php"
Dann drücken Sie wahrscheinlich die Eingabetaste und stellen fest, dass Sie zu viele Dateien aus Verzeichnissen erhalten, die Sie nicht möchten. Lassen Sie uns /Medien ausschließen, um zu vermeiden, dass Sie Ihre montierten Laufwerke durchsuchen.
Sie sollten jetzt nur den folgenden Befehl anhängen:
-print -o -path '/media' -prune
Der endgültige Befehl lautet also:
find / -name "*.php" -print -o -path '/media' -prune
............... | <--- Include ---> | .................... | <- -------- Ausschließen ----------> |
Ich denke, diese Struktur ist viel einfacher und korreliert mit dem richtigen Ansatz
Hinzu kommt zu den Ratschlägen in anderen Antworten (ich habe keinen Repräsentanten, um Antworten zu erstellen) ...
Beim Kombinieren -prune
Bei anderen Ausdrücken gibt es einen subtilen Verhaltensunterschied, je nachdem, welche Ausdrücke verwendet werden.
@Laurence Gonsalves 'Beispiel findet die "*.foo" -Dateien, die nicht unter ".snapshot" -Verzeichnungen sind:-
find . -name .snapshot -prune -o -name '*.foo' -print
Dieser etwas andere Short-Hand wird jedoch möglicherweise versehentlich auch die auflisten .snapshot
Verzeichnis (und alle verschachtelten .snapshot-Verzeichnisse):-
find . -name .snapshot -prune -o -name '*.foo'
Der Grund ist (gemäß der Manpage auf meinem System):-
Wenn der gegebene Ausdruck keine der Vorwahlen -exec, -ls, -ok oder -print enthält, wird der gegebene Ausdruck wirksam ersetzt durch:
(gegebene_expression) -print
Das zweite Beispiel entspricht dem Eintritt in Folgendes, wodurch die Gruppierung von Begriffen geändert wird:-
find . \( -name .snapshot -prune -o -name '*.foo' \) -print
Dies wurde zumindest auf Solaris 5.10 gesehen. Nachdem ich ungefähr 10 Jahre lang verschiedene Geschmacksrichtungen von *Nix verwendet habe, habe ich erst kürzlich aus einem Grund gesucht, warum dies geschieht.
Prune ist ein Recurse bei keinem Verzeichnisschalter.
Von der Mannseite
Wenn -Tepth nicht gegeben ist, wahr; Wenn die Datei ein Verzeichnis ist, steigen Sie nicht hinein. Wenn -Tepth gegeben ist, falsch; Kein Effekt.
Grundsätzlich wird es nicht in Sub -Verzeichnisse eingehen.
Nehmen Sie dieses Beispiel:
Sie haben die folgenden Verzeichnisse
- /home/test2
- /home/test2/test2
Wenn du läufst find -name test2
:
Es wird beide Verzeichnisse zurückgeben
Wenn du läufst find -name test2 -prune
:
Es kehrt nur/home/test2 zurück, da es nicht in/home/test2 abfällt, um/home/test2/test2 zu finden
Ich bin kein Experte darin (und diese Seite war sehr hilfreich zusammen mit http://mywiki.wooledge.org/usingfind)
Gerade bemerkt -path
ist für einen Weg, den Übereinstimmung mit der String/Pfad, die kurz danach kommt find
(.
in diesen Beispielen) wo as -name
entspricht allen Grundnamen.
find . -path ./.git -prune -o -name file -print
Blockiert das .git -Verzeichnis in Ihrem aktuellen Verzeichnis ( Wie Ihre Feststellung in .
)
find . -name .git -prune -o -name file -print
Blockiert alle .git -Unterverzeichnisse rekursiv.
Beachten Sie das ./
ist extrem wichtig !! -path
muss einen Pfad entsprechen, der verankert ist .
oder was auch immer kommt, kurz nach dem Finden Wenn Sie übereinstimmen, ohne dass es aus der anderen Seite des oder 'ist-o
') Da wird es wahrscheinlich nicht beschnitten! Ich war mir dessen naiv nicht bewusst und es brachte mich dazu, -Path zu verwenden, wenn es großartig ist, wenn Sie nicht das gesamte Unterverzeichnis mit dem gleichen Grundnamen beschneiden möchten: D.
Zeigen Sie alles, einschließlich Dir selbst, aber nicht seinen langweiligen Inhalt:
find . -print -name dir -prune
Wenn Sie hier alle guten Antworten lesen, ist mein Verständnis jetzt, dass die folgenden die gleichen Ergebnisse zurückgeben:
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 es immer noch alles in dir1 durchsucht. Ich denke, die eigentliche Frage ist, wie es geht -or
unerwünschte Ergebnisse aus, ohne sie tatsächlich zu durchsuchen.
Ich denke, Prune bedeutet also keine anständigen Vergangenheit, sondern markieren Sie es wie getan ...
http://www.gnu.org/software/findutils/manual/html_mono/find.html"Dies ist jedoch nicht auf die Auswirkung der '-prunen'-Aktion zurückzuführen (die nur weitere Abstammung verhindert, stellt nicht sicher, dass wir diesen Element ignorieren). Stattdessen ist dieser Effekt auf die Verwendung von' -o 'zurückzuführen. Da die linke Seite des „oder“ Zustands für ./src/emacs gelungen ist, ist es für diese bestimmte Datei überhaupt nicht erforderlich, die rechte Seite ('-Druck') zu bewerten.
find
Erstellt eine Liste von Dateien. Es wendet das Prädikat an, das Sie jedem zur Verfügung gestellt haben, und gibt diejenigen zurück, die passieren.
Diese Idee das -prune
bedeutet für mich wirklich verwirrend. Sie können eine Datei ohne Pflaumen ausschließen:
find -name 'bad_guy' -o -name 'good_guy' -print // good_guy
Alle -prune
Verändert das Verhalten der Suche. Wenn das aktuelle Spiel ein Verzeichnis ist, heißt es "Hey find
, diese Datei, die Sie gerade abgestimmt haben, steigen Sie nicht hinein. ". Es wird nur diesen Baum (aber nicht die Datei selbst) aus der Liste der Dateien zu suchen.
Es sollte benannt werden -dont-descend
.