find: prune non ignora il percorso specificato


13

Devo escludere .gitdalla mia findricerca. Per raggiungere questo obiettivo, sto usando l' -path ./.git -pruneinterruttore:

$ find . -path ./.git -prune -o \( -type f -o -type l -o -type d \) | grep '.git'
./.git

Tuttavia, anche se questo salta il contenuto della directory .git, elenca la directory stessa. Funziona quando aggiungo-path ./.git -prune -o -print -a

find . -path ./.git -prune -o -print -a \( -type f -o -type l -o -type d \) | grep '.git'

Perché è necessario? Ho pensato che entrambi i comandi dovessero avere lo stesso output. La seconda sintassi è piuttosto brutta.


4
Hai bisogno di un -print, altrimenti l'implicito si -printapplica all'intera condizione
Stéphane Chazelas il


Risposte:


3

La manpagina per finddà:

-prune True; if the file is a directory, do not  descend  into  it.  If
      -depth  is  given,  false;  no  effect.  Because -delete implies
      -depth, you cannot usefully use -prune and -delete together.

Quindi nel primo esempio non è così -path ./.git -prunefalso e quindi l'azione predefinita ( -print) non verrebbe chiamata, quindi la linea viene stampata.


22

Ero confuso sul perché anche le directory potate venivano stampate dal findcomando e alcuni altri intricati dettagli su come -prunefunzionava, ma sono stato in grado di capirlo con alcuni esempi.

Per eseguire gli esempi seguenti, creare le seguenti directory e file.

mkdir aa
mkdir bb
touch file1
touch aa/file1
touch bb/file3

Per creare questa struttura:

$ tree

.
├── aa
   └── file1
├── bb
   └── file3
└── file1

Ora usa trova per cercare le directory chiamate aa. Nessun problema qui.

$ find . -type d -name aa
./aa

Cerca tutte le directory diverse da aa e otteniamo la directory corrente .e ./bb, il che ha anche senso.

$ find . -type d ! -name aa
.
./bb

Fin qui tutto bene, ma quando usiamo -prune, find restituisce la directory che stiamo potando, che inizialmente mi ha confuso perché mi aspettavo che restituisse tutte le altre directory e non quella che è stata potata.

$ find . -type d -name aa -prune
./aa

Il motivo per cui restituisce la directory che viene eliminata è spiegato, non nella -prunesezione delle pagine man come indicato nella risposta di Timo , ma nella EXPRESSIONSsezione:

Se l'espressione non contiene azioni diverse da -prune,  -printviene eseguita su tutti i file per i quali l'espressione è vera.

il che significa che, poiché l'espressione corrisponde al aanome della directory, allora l'espressione verrà valutata come vera e verrà stampata perché find aggiunge implicitamente -printa alla fine dell'intero comando. Non aggiungerà -print, tuttavia, se si aggiunge intenzionalmente l'azione -o -printalla fine:

find . -type d -name aa -prune -o -print
.
./file1
./bb
./bb/file3

Qui il comando find NON aggiunge più un implicito -print, quindi la directory che stiamo potando ( aa) non verrà stampata.

Quindi, infine, se aggiungiamo una clausola che cerca i file con un modello di nome file file*dopo il -o, allora devi mettere un -printalla fine di quella seconda clausola in questo modo:

find . \( -type d -name aa -prune \) -o \( -type f -name 'file*' -print \)
./file1
./bb/file3

Il motivo per cui funziona è lo stesso: se non si inserisce a -printnella seconda clausola, quindi poiché non esiste alcuna azione diversa -prunedall'azione, find aggiungerà -printautomaticamente a THE END del comando, causando la -prunestampa della clausola directory potata:

find . \( \( -type d -name aa -prune \) -o \( -type f -name 'file*' \) \) -print
./aa
./file1
./bb/file3

In generale, è necessario inserire il -printcomando nella seconda clausola. Se lo metti nel mezzo come ha fatto il poster originale, non funzionerà correttamente perché i file che verranno eliminati verranno stampati immediatamente e la seconda clausola non avrà la possibilità di scegliere i file desiderati:

find . \( -type d -name aa -prune -o -print \) -o \( -type f -name 'file*' \)
.
./file1
./bb
./bb/file3

Quindi, sfortunatamente, il poster originale ha sbagliato il comando sopra posizionandolo -printnel posto sbagliato. Potrebbe aver funzionato per il suo caso specifico, ma non funziona nel caso generale.

Ci sono migliaia di persone che hanno difficoltà a capire come -prunefunziona. La findpagina man dovrebbe essere aggiornata per evitare la confusione infinita in tutto il mondo su questo comando.


La mia pagina man (Arch Linux, find-4.6.0) dice "Se l'intera espressione non contiene azioni diverse da -prune o -print, -print viene eseguito su tutti i file per i quali l'intera espressione è vera." Ma funziona come descritto.
x-yuri,

0

dalla manpagina,

Per ignorare un intero albero di directory, utilizzare -prune anziché controllare tutti i file nella struttura. Ad esempio, per saltare la directory `src / emacs 'e tutti i file e le directory sottostanti e stampare i nomi degli altri file trovati, fare qualcosa del genere:

find . -path ./src/emacs -prune -o -print

Quindi, può essere che puoi usare:

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

Questo non elenca la .gitdirectory.

per specificare un nome di file, puoi fare così:

find . -path ./.git -prune , -name filename

Si prega di notare l' ,operatore virgola.


-1

Ecco un'alternativa veloce e sporca:

find | fgrep -v /.git

Semplicemente non ricordo findla complessa sintassi ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.