Verwenden Sie den Befehl find, schließen Sie jedoch Dateien in zwei Verzeichnissen aus

85

Ich möchte Dateien finden, die mit enden _peaks.bed, aber Dateien in den Ordnern tmpund ausschließen scripts.

Mein Befehl lautet wie folgt:

 find . -type f \( -name "*_peaks.bed" ! -name "*tmp*" ! -name "*scripts*" \)

Aber es hat nicht funktioniert. Die Dateien in tmpund scriptOrdner werden weiterhin angezeigt.

Hat jemand Ideen dazu?

Hanfei Sun.
quelle

Antworten:

187

So können Sie das angeben mit find:

find . -type f -name "*_peaks.bed" ! -path "./tmp/*" ! -path "./scripts/*"

Erläuterung:

  • find . - Starten Sie die Suche aus dem aktuellen Arbeitsverzeichnis (standardmäßig rekursiv).
  • -type f- Geben Sie an, finddass Sie nur Dateien in den Ergebnissen haben möchten
  • -name "*_peaks.bed" - Suchen Sie nach Dateien, deren Name auf endet _peaks.bed
  • ! -path "./tmp/*" - Schließen Sie alle Ergebnisse aus, deren Pfad mit beginnt ./tmp/
  • ! -path "./scripts/*" - Schließen Sie auch alle Ergebnisse aus, deren Pfad mit beginnt ./scripts/

Testen der Lösung:

$ mkdir a b c d e
$ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
$ find . -type f ! -path "./a/*" ! -path "./b/*"

./d/4
./c/3
./e/a
./e/b
./e/5

Sie waren ziemlich nah dran, die -nameOption berücksichtigt nur den Basisnamen, wobei -pathder gesamte Pfad berücksichtigt wird =)

Sampson-Chen
quelle
Gute Arbeit. Sie haben jedoch eines der Dinge vergessen, die das OP wollte, um Dateien zu finden, die mit enden _peaks.bed.
Alex
2
Dies verwendet eine Reihe von Erweiterungen in GNU find, aber da die Frage mit Linux gekennzeichnet ist, ist dies kein Problem. Gute Antwort.
Jonathan Leffler
1
Ein kurzer Hinweis: Wenn Sie .bei Ihrer ersten Suchaufforderung verwenden, müssen Sie ihn in jedem Pfad verwenden, den Sie ausschließen. Die Pfadübereinstimmung ist ziemlich streng und führt keine Fuzzy-Suche durch. Also, wenn Sie es verwenden, wird es find / -type f -name *.bed" ! -path "./tmp/"nicht funktionieren. Sie müssen ! -path "/tmp"es glücklich machen müssen.
Peelman
3
Es ist wichtig zu beachten, dass das * wichtig ist. $ ! -path "./directory/*"
Thomas Bennett
3
In den Manpages heißt es: "Um einen ganzen Verzeichnisbaum zu ignorieren, verwenden Sie -prunenicht jede Datei im Baum, sondern überprüfen Sie sie." Wenn Ihre ausgeschlossenen Verzeichnisse sehr tief sind oder Unmengen von Dateien enthalten und Sie Wert auf Leistung -prunelegen, verwenden Sie stattdessen die Option.
15.
8

Hier ist eine Möglichkeit, wie Sie es tun können ...

find . -type f -name "*_peaks.bed" | egrep -v "^(./tmp/|./scripts/)"
Alex
quelle
2
Dies hat den Vorteil, mit jeder Version von findund nicht nur mit GNU zu arbeiten find. Die Frage ist jedoch mit Linux gekennzeichnet, sodass dies nicht kritisch ist.
Jonathan Leffler
0

Versuchen Sie etwas wie

find . \( -type f -name \*_peaks.bed -print \) -or \( -type d -and \( -name tmp -or -name scripts \) -and -prune \)

und sei nicht zu überrascht, wenn ich es ein bisschen falsch verstanden habe. Wenn das Ziel ein Exec ist (anstelle von Print), ersetzen Sie es einfach.

DrC
quelle
0

Für mich hat diese Lösung bei einem Befehlsausführen mit Suchen nicht funktioniert. Ich weiß nicht wirklich warum, also ist meine Lösung

find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

Erklärung: wie sampson-chen eins mit den Zusätzen von

-prune - ignoriere den Prozedurpfad von ...

-o - Wenn keine Übereinstimmung vorliegt, drucken Sie die Ergebnisse aus (beschneiden Sie die Verzeichnisse und drucken Sie die verbleibenden Ergebnisse).

18:12 $ mkdir a b c d e
18:13 $ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
18:13 $ find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

gzip: . is a directory -- ignored
gzip: ./a is a directory -- ignored
gzip: ./b is a directory -- ignored
gzip: ./c is a directory -- ignored
./c/3:    0.0% -- replaced with ./c/3.gz
gzip: ./d is a directory -- ignored
./d/4:    0.0% -- replaced with ./d/4.gz
gzip: ./e is a directory -- ignored
./e/5:    0.0% -- replaced with ./e/5.gz
./e/a:    0.0% -- replaced with ./e/a.gz
./e/b:    0.0% -- replaced with ./e/b.gz
al3x2ndru
quelle
Die akzeptierte Antwort hat nicht funktioniert, aber das funktioniert. Mit Pflaume , find . -path ./scripts -prune -name '*_peaks.bed' -type f. Nicht sicher, wie mehrere Verzeichnisse ausgeschlossen werden sollen. Dies listet auch das ausgeschlossene Verzeichnis der obersten Ebene auf, obwohl typees angegeben ist. Das Ausschließen über Grep scheint einfacher zu sein, es sei denn, Sie möchten Prune verwenden, um den Suchvorgang zu beschleunigen.
Mohnish
Ich hatte auch Probleme, mehrere Verzeichnisse auszuschließen, aber die obigen Kommentare gaben mir eine Antwort, die funktionierte. Ich verwende mehrere Instanzen von '-not -path' und füge in jeden Pfadausdruck das vollständige Präfix ein, das im ersten Parameter verwendet wird, um 'zu finden' und jeweils mit einem Sternchen zu beenden (und alle Punkte zu maskieren).
Jetset
0

Sie können unten versuchen:

find ./ ! \( -path ./tmp -prune \) ! \( -path ./scripts -prune \) -type f -name '*_peaks.bed'
Jacky Jiang
quelle
2
Bei einer alten Frage wie dieser (4 Jahre!) Möchten Sie erklären, warum diese neue Antwort besser oder anders ist, nicht nur "Dump" -Code.
Nic3500
0

Verwenden

find \( -path "./tmp" -o -path "./scripts" \) -prune -o  -name "*_peaks.bed" -print

oder

find \( -path "./tmp" -o -path "./scripts" \) -prune -false -o  -name "*_peaks.bed"

oder

find \( -path "./tmp" -path "./scripts" \) ! -prune -o  -name "*_peaks.bed"

Die Reihenfolge ist wichtig. Es wird von links nach rechts ausgewertet. Beginnen Sie immer mit dem Pfadausschluss.

Erläuterung

Verwenden Sie -not(oder !) nicht, um das gesamte Verzeichnis auszuschließen. Verwenden Sie -prune. Wie im Handbuch erklärt:

−prune    The primary shall always evaluate as  true;  it
          shall  cause  find  not  to descend the current
          pathname if it is a directory.  If  the  −depth
          primary  is specified, the −prune primary shall
          have no effect.

und im GNU Handbuch finden:

-path pattern
              [...]
              To ignore  a  whole
              directory  tree,  use  -prune rather than checking
              every file in the tree.

Wenn Sie verwenden -not -path "./pathname", wertet find den Ausdruck für jeden Knoten unter aus "./pathname".

Suchausdrücke sind nur eine Zustandsbewertung.

  • \( \)- Gruppenoperation (Sie können verwenden -path "./tmp" -prune -o -path "./scripts" -prune -o, aber es ist ausführlicher).
  • -path "./script" -prune- Wenn -pathtrue zurückgegeben wird und ein Verzeichnis ist, geben Sie true für dieses Verzeichnis zurück und steigen Sie nicht in dieses Verzeichnis ab.
  • -path "./script" ! -prune- es bewertet als (-path "./script") AND (! -prune). Es setzt das "immer wahr" der Pflaume auf immer falsch zurück. Das Drucken "./script"als Match wird vermieden .
  • -path "./script" -prune -false- Da -pruneimmer true zurückgegeben wird, können Sie dem folgen -false, um dasselbe zu tun wie !.
  • -o- ODER-Operator. Wenn zwischen zwei Ausdrücken kein Operator angegeben ist, wird standardmäßig der Operator AND verwendet.

Daher \( -path "./tmp" -o -path "./scripts" \) -prune -o -name "*_peaks.bed" -printwird erweitert auf:

[ (-path "./tmp" OR -path "./script") AND -prune ] OR ( -name "*_peaks.bed" AND print )

Der Druck ist hier wichtig, weil er ohne erweitert wird auf:

{ [ (-path "./tmp" OR -path "./script" )  AND -prune ]  OR (-name "*_peaks.bed" ) } AND print

-printwird durch find hinzugefügt - deshalb müssen Sie es die meiste Zeit nicht in Ihren Ausdruck einfügen. Und da -prunetrue zurückgegeben wird, werden "./script" und "./tmp" ausgegeben.

Bei den anderen ist dies nicht erforderlich, da wir -pruneauf immer false zurückgegeben haben.

Hinweis: Sie können verwenden, um find -D opt expr 2>&1 1>/dev/nullzu sehen, wie es optimiert und erweitert wird, um
find -D search expr 2>&1 1>/dev/nullzu sehen, welcher Pfad überprüft wird.

f380cedric
quelle