Come escludere una directory in find. comando


1380

Sto cercando di eseguire un find comando per tutti i file JavaScript, ma come posso escludere una directory specifica?

Ecco il findcodice che stiamo usando.

for file in $(find . -name '*.js')
do 
  java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done

10
Qual è la directory che devi escludere?
L'archetipo Paolo,

11
È meglio usare find ... | while read -r file .... Inoltre, è meglio accettare e valutare le risposte.
In pausa fino a nuovo avviso.

mentre la lettura è lenta, perché in è più veloce
mpapis,

18
@mpapis durante la lettura gestisce correttamente le linee complete con spazi bianchi.
Jean-Philippe Pellet,

1
Basta eseguire questo in una cartella con i file con gli spazi nei loro nomi: for file in $(find .); do echo "$file"; done. I nomi con spazi sono divisi, cosa che non vogliamo.
Jean-Philippe Pellet,

Risposte:


1140

Usa l' -pruneinterruttore. Ad esempio, se si desidera escludere la miscdirectory, basta aggiungere a -path ./misc -prune -oal comando find:

find . -path ./misc -prune -o -name '*.txt' -print

Ecco un esempio con più directory:

find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print

Qui escludiamo dir1 , dir2 e dir3 , poiché nelle findespressioni è un'azione che agisce sui criteri -path dir1 -o -path dir2 -o -path dir3(se dir1 o dir2 o dir3 ), ANDed with type -d.

Ulteriore azione è -o print, basta stampare.


89
Hmm. Questo non funziona neanche per me poiché includerà la directory ignorata "./misc" nell'output.
Theuni,

84
@Theuni Probabilmente non ha funzionato per te perché non hai aggiunto -printesplicitamente (o qualsiasi altra azione) dopo -name. In tal caso, entrambi i "lati" della -ostampa finiscono, mentre se si utilizza -print, stampa solo quel lato.
Daniel C. Sobral,

4
Dalla manpage: Because -delete implies -depth, you cannot usefully use -prune and -delete together.Quindi, come posso fare per eliminare con find se voglio escludere directory specifiche dalla cancellazione?
Jānis Elmeris,

15
Per rimuovere l'intero stessa directory dai risultati uso: find . -not -path "./.git*". L'uso ./dir*invece di ./dir/*rimuove la directory e i contenuti dall'output.
micahblu,

64
Questa domanda e la confusione nelle risposte sono manifeste su quanto male trova l'interfaccia utente di ricerca su ciò di cui le persone hanno bisogno.
Johannes Overmann,

1932

Se -prunenon funziona per te, questo:

find -name "*.js" -not -path "./directory/*"

Avvertenza: richiede di attraversare tutte le directory indesiderate.


86
Uno dei commenti nella risposta accettata sottolinea il problema. -prunenon esclude la directory stessa, esclude il suo contenuto, il che significa che otterrai una linea indesiderata nell'output con la directory esclusa.
GetFree

96
Bella risposta. Aggiungo a questo che è possibile escludere una directory a QUALSIASI livello modificando la prima .in *. quindi find -name "*.js" -not -path "*/omitme/*"ometterei i file da una directory denominata "omitme" a qualsiasi livello di profondità.
DeeDee,

83
Attraversa comunque tutta la directory indesiderata. Sto aggiungendo la mia risposta. :-)
Daniel C. Sobral,

18
Nota, tuttavia, che l'opzione di prugna non funziona solo se non la usi -printesplicitamente.
Daniel C. Sobral,

39
Sarebbe meglio dire "Questa è un'alternativa all'utilizzo di -prune". Le risposte che suggeriscono che -prune non sono chiaramente sbagliate, semplicemente non sono come faresti tu.
Jimbo

458

Trovo quanto segue più facile da ragionare rispetto ad altre soluzioni proposte:

find build -not \( -path build/external -prune \) -name \*.js
# you can also exclude multiple paths
find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js

Nota importante: i percorsi digitati dopo -pathdevono corrispondere esattamente a ciò che findverrebbe stampato senza esclusione. Se questa frase ti confonde, assicurati di usare percorsi completi attraverso l' intero comando in questo modo:find /full/path/ -not \( -path /full/path/exclude/this -prune \) ... . Vedi la nota [1] se desideri una migliore comprensione.

Dentro \(ed \)è un'espressione che corrisponderà esattamente build/external (vedi nota importante sopra) e, in caso di successo, eviterà di attraversare qualsiasi cosa sotto . Questo viene quindi raggruppato come una singola espressione con la parentesi di escape e prefissato con il -notquale findsalterà tutto ciò che è stato abbinato a quell'espressione.

Ci si potrebbe chiedere se l'aggiunta -notnon renderà tutti gli altri file nascosti dalla -prunericomparsa, e la risposta è no. La via-prune funziona è che qualsiasi cosa che, una volta raggiunta, i file sotto quella directory vengano definitivamente ignorati.

Questo deriva da un caso d'uso reale, in cui avevo bisogno di chiamare yui-compressore su alcuni file generati da Wintersmith, ma tralasciare altri file che devono essere inviati così come sono.


Nota [1] : se si desidera escludere /tmp/foo/bared eseguire " find /tmp \(..." in questo modo, è necessario specificare -path /tmp/foo/bar. Se invece corri a trovare in questo modo cd /tmp; find . \(..., devi specificare -path ./foo/bar.


37
Risposta eccezionale, grazie. Funziona ed è scalabile (leggibile) per più esclusioni. Siete gentiluomini e studiosi signore. Grazie per l'esempio per più esclusioni
Freedom_Ben

7
Questo non funziona se voglio usare l'opzione -delete:find . -not \( -path ./CVS -prune \) -type f -mtime +100 -delete find: The -delete action atomatically turns on -depth, but -prune does nothing when -depth is in effect. If you want to carry on anyway, just explicitly use the -depth option.
Jānis Elmeris

17
@Janis Puoi usare -exec rm -rf {} \;invece di -delete.
Daniel C. Sobral,

11
Esaminando l'output di find, questo è davvero ovvio, ma mi ha fatto scattare. Se siete alla ricerca nella directory corrente (specificando .come il percorso di ricerca, o non specificare uno a tutti), è molto probabile che desidera che il modello dopo -pathper cominciare ./, ad esempio: find -not \( -path ./.git -prune \) -type f.
Zantier,

7
Una variante più precisa (e compatibile POSIX) di questo metodo: find searchdir \! \( -type d \( -path './excludedir/*' -o -path './excludedir2/*' -o -path './excludedir3/*' \) -prune \)seguita da tutte le condizioni che dovrebbero corrispondere a ciò che stai cercando.
Walf,

218

C'è chiaramente un po 'di confusione su quale dovrebbe essere la sintassi preferita per saltare una directory.

Opinione GNU

To ignore a directory and the files under it, use -prune

Dalla GNU trova la pagina man

Ragionamento

-prunesmette finddi scendere in una directory. Basta specificare -not -pathscenderà comunque nella directory ignorata , ma -not -pathsarà falso ogni voltafind testa ogni file.

Problemi con -prune

-prune fa quello che è previsto, ma ci sono ancora alcune cose di cui devi occuparti quando lo usi.

  1. find stampa la directory eliminata.

    • VERO È un comportamento previsto, semplicemente non vi discende. Per evitare di stampare del tutto la directory, utilizzare una sintassi che la ometta logicamente.
  2. -prunefunziona solo con -printe senza altre azioni.

    • NON VERO . -prunefunziona con qualsiasi azione tranne -delete. Perché non funziona con Elimina? Per -deletefunzionare, trova la necessità di attraversare la directory in ordine DFS, poiché -deleteprima cancellerà le foglie, quindi i genitori delle foglie, ecc ... Ma per specificare il -prunesenso, finddevi premere una directory e smettere di discenderla, che chiaramente non ha senso con -deptho -deletesu.

Prestazione

Ho impostato un semplice test delle tre risposte più votate su questa domanda (sostituito -printcon -exec bash -c 'echo $0' {} \;per mostrare un altro esempio di azione). I risultati sono sotto

----------------------------------------------
# of files/dirs in level one directories
.performance_test/prune_me     702702    
.performance_test/other        2         
----------------------------------------------

> find ".performance_test" -path ".performance_test/prune_me" -prune -o -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 23513814

> find ".performance_test" -not \( -path ".performance_test/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 10670141

> find ".performance_test" -not -path ".performance_test/prune_me*" -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 864843145

Conclusione

Sia la sintassi di f10bit e la sintassi di Daniel C. Sobral hanno 10-25ms per funzionare in media. La sintassi di GetFree , che non usa -prune, ha richiesto 865ms. Quindi, sì, questo è un esempio piuttosto estremo, ma se ti preoccupi del tempo di esecuzione e stai facendo qualcosa di remoto, dovresti usare-prune .

Nota La sintassi di Daniel C. Sobral ha eseguito il meglio delle due -prunesintassi; ma sospetto fortemente che questo sia il risultato di un po 'di memorizzazione nella cache in quanto il cambio dell'ordine in cui i due sono stati eseguiti ha prodotto il risultato opposto, mentre la versione non potata è stata sempre più lenta.

Test script

#!/bin/bash

dir='.performance_test'

setup() {
  mkdir "$dir" || exit 1
  mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z" \
    "$dir/other"

  find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} \;
  find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} \;
  touch "$dir/other/foo"
}

cleanup() {
  rm -rf "$dir"
}

stats() {
  for file in "$dir"/*; do
    if [[ -d "$file" ]]; then
      count=$(find "$file" | wc -l)
      printf "%-30s %-10s\n" "$file" "$count"
    fi
  done
}

name1() {
  find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo "$0"'  {} \;
}

name2() {
  find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
}

name3() {
  find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} \;
}

printf "Setting up test files...\n\n"
setup
echo "----------------------------------------------"
echo "# of files/dirs in level one directories"
stats | sort -k 2 -n -r
echo "----------------------------------------------"

printf "\nRunning performance test...\n\n"

echo \> find \""$dir"\" -path \""$dir/prune_me"\" -prune -o -exec bash -c \'echo \"\$0\"\'  {} \\\;
name1
s=$(date +%s%N)
name1_num=$(name1 | wc -l)
e=$(date +%s%N)
name1_perf=$((e-s))
printf "  [# of files] $name1_num [Runtime(ns)] $name1_perf\n\n"

echo \> find \""$dir"\" -not \\\( -path \""$dir/prune_me"\" -prune \\\) -exec bash -c \'echo \"\$0\"\' {} \\\;
name2
s=$(date +%s%N)
name2_num=$(name2 | wc -l)
e=$(date +%s%N)
name2_perf=$((e-s))
printf "  [# of files] $name2_num [Runtime(ns)] $name2_perf\n\n"

echo \> find \""$dir"\" -not -path \""$dir/prune_me*"\" -exec bash -c \'echo \"\$0\"\' {} \\\;
name3
s=$(date +%s%N)
name3_num=$(name3 | wc -l)
e=$(date +%s%N)
name3_perf=$((e-s))
printf "  [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n"

echo "Cleaning up test files..."
cleanup

18
Grazie per un'ottima analisi. Per quanto riguarda "Sospetto fortemente che questo sia il risultato di un po 'di cache" puoi eseguire questo comando: sudo sh -c "free && sync && echo 3> / proc / sys / vm / drop_caches && free" per cancellare la cache (vedi unix. stackexchange.com/questions/87908/… ).
ndemou,

Dopo alcuni test su quei due con -pruneposso dire che raramente c'è alcuna differenza. Tieni presente che quale comando inizia prima trarrà vantaggio dalle prestazioni della cpu, il successivo riscaldamento della cpu> calo delle prestazioni causa un rallentamento minore (ho eliminato la cache prima di ogni comando come suggerimento @ndemou)
Huy.PhamNhu

Prova a cambiare il numero tra name1() name2() name3()nello script di test @BroSlow sopra per cambiare l'ordine di esecuzione per avere una visione di ciò che ho detto. Nella vita reale, è impercettibile tra quei due però.
Huy.PhamNhu,

Applausi. Grazie per questa risposta di qualità.
Stphane,

Non dovresti essere -o che significa o. quindi stai potando nel primo passo e poi dimenticando tutto nel prossimo.
mmm

97

Questo è l'unico che ha funzionato per me.

find / -name MyFile ! -path '*/Directory/*'

Ricerca di "MyFile" escluso "Directory". Dai enfasi alle stelle *.


13
Questo metodo funziona su macOS mentre la risposta accettata no. So che la domanda originale è per Linux.
Xavier Rubio Jansana,

5
Nota che puoi aggiungere più ! -path '*/Directory/*'comandi al tuo comando in successione per ignorare più directory
Aclwitt,

Funziona su MacOS ma non su Linux ... confermato
Marcello de Sales

In una docker containerfunziona solo consh -c "find..."
Marcello di Sales

@Marcello de Sales Ovviamente funziona su Linux.
DimiDak,

59

Un'opzione sarebbe quella di escludere tutti i risultati che contengono il nome della directory con grep. Per esempio:

find . -name '*.js' | grep -v excludeddir

44
Ciò renderà la tua ricerca molto lenta
Dorian,

6
Questo ha funzionato per me, altri (che usano -prune) - no.
Andron,

7
Lento in grandi risultati, ma utile in serie più piccole. Ma come escludere più directory usando grep? Ovviamente in questo modo: find . -name '*.js' | grep -v excludeddir | grep -v excludedir2 | grep -v excludedir3ma potrebbe esserci un modo in cui solo un grep.
Timo Kähkönen,

6
Se si desidera eseguire più greps allora si sarebbe meglio scriverlo come le espressioni regolari: egrep -v '(dir1|dir2|dir3)'. Tuttavia, in questo caso specifico, sarebbe meglio escludere le directory al findsuo interno .
Laurence,

1
sì, e non hai bisogno di parentesi e sarebbe meglio usare ^ per assicurarsi che corrisponda a directoryname all'inizio della stringa, ad esempio: find. -name '* .js' | egrep -v "^ \ ./ excluseddir1 | ^ \ ./ excleddir2"
Sofija

41

Preferisco la -notnotazione ... è più leggibile:

find . -name '*.js' -and -not -path directory

5
Siamo spiacenti, non funziona. La pagina man per finddice: "Per ignorare una directory e i file sotto di essa, usa -prune".
Christian Davén,

8
Questo è sbagliato. Non impedisce a find di entrare nella directory e attraversare tutti i file all'interno.
GetFree

find . -iname '*' -and -not -path './somePath'non impedisce che entri in detta directory.
Lemmings19

Questo mi ha aiutato con .git path find . -iname '*' -not -path './.git/*'
Mark Shust al M.academy il

7
@rane: più specificamente find . -not -path "*/.git*"sarebbe quello che vuoi.
Ben

20

Utilizzare l'opzione -prune. Quindi, qualcosa del tipo:

find . -type d -name proc -prune -o -name '*.js'

'-Type d -name proc -prune' cerca solo le directory chiamate proc da escludere.
'-O' è un operatore 'OR'.


1
Questa è l'unica soluzione "trova" pura che ha funzionato per me. Le directory che desideravo escludere NON sono immediatamente sotto la directory di lavoro corrente.
Lambart,

5
Tuttavia, l'aggiunta -printalla fine può migliorare i risultati. find . -type d -name .hg -prune -o -name dataignorato il contenuto delle (multiple) .hgdirectory, ma ha elencato le .hgdirectory stesse. Con -print, elencava solo le directory "dati" che stavo cercando.
Lambart,

19

-prune sicuramente funziona ed è la risposta migliore perché impedisce di scendere nella directory che si desidera escludere. -not -pathche cerca ancora la directory esclusa, semplicemente non stampa il risultato, il che potrebbe essere un problema se la directory esclusa è montata sul volume di rete o non si dispone delle autorizzazioni.

La parte difficile è che findè molto particolare riguardo all'ordine degli argomenti, quindi se non li capisci bene, il tuo comando potrebbe non funzionare. L'ordine degli argomenti è generalmente tale:

find {path} {options} {action}

{path}: Metti prima tutti gli argomenti relativi al percorso, come . -path './dir1' -prune -o

{options}: Ottengo il maggior successo mettendo -name, -iname, etcl'ultima opzione in questo gruppo. Per esempio-type f -iname '*.js'

{action}: Ti consigliamo di aggiungere -printquando si utilizza-prune

Ecco un esempio funzionante:

# setup test
mkdir dir1 dir2 dir3
touch dir1/file.txt; touch dir1/file.js
touch dir2/file.txt; touch dir2/file.js
touch dir3/file.txt; touch dir3/file.js

# search for *.js, exclude dir1
find . -path './dir1' -prune -o -type f -iname '*.js' -print

# search for *.js, exclude dir1 and dir2
find . \( -path './dir1' -o -path './dir2' \) -prune -o -type f -iname '*.js' -print

16

Questo è il formato che ho usato per escludere alcuni percorsi:

$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"

Ho usato questo per trovare tutti i file non nei percorsi ". *":

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"

Ho provato questo e scende ancora nelle directory, quindi la velocità non è decisamente migliorata.
Br.

10

L'approccio -path -prune funziona anche con i caratteri jolly nel percorso. Ecco un'istruzione find che troverà le directory per un server git che serve più repository git tralasciando le directory interne git:

find . -type d \
   -not \( -path */objects -prune \) \
   -not \( -path */branches -prune \) \
   -not \( -path */refs -prune \) \
   -not \( -path */logs -prune \) \
   -not \( -path */.git -prune \) \
   -not \( -path */info -prune \) \
   -not \( -path */hooks -prune \)  

9

Per escludere più directory:

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)

Per aggiungere directory, aggiungere -o -path "./dirname/*":

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)

Ma forse dovresti usare un'espressione regolare , se ci sono molte directory da escludere.


9

Ci sono molte buone risposte, mi ci è voluto solo un po 'di tempo per capire a cosa serviva ogni elemento del comando e la logica che stava dietro.

find . -path ./misc -prune -o -name '*.txt' -print

find inizierà a trovare file e directory nella directory corrente, quindi il file find . .

L' -oopzione rappresenta un OR logico e separa le due parti del comando:

[ -path ./misc -prune ] OR [ -name '*.txt' -print ]

Qualsiasi directory o file che non sia la directory ./misc non supererà il primo test -path ./misc. Ma saranno testati contro la seconda espressione. Se il loro nome corrisponde al modello *.txtche vengono stampati, a causa del-print dell'opzione.

Quando find raggiunge la directory ./misc, questa directory soddisfa solo la prima espressione. Quindi l' -pruneopzione verrà applicata ad esso. Indica al comando find di non esplorare quella directory. Quindi qualsiasi file o directory in ./misc non verrà nemmeno esplorato da find, non verrà testato rispetto alla seconda parte dell'espressione e non verrà stampato.


Tutti hanno una soluzione, ma la tua l'ha spiegata al meglio. Ero irremovibile di usare prima -name anziché -path. La tua spiegazione era adeguata per arrivare a quello che volevo. trova . -name "* .txt" -print -o -path ./misc -prune
Vendetta V

7

Per una soluzione funzionante (testata su Ubuntu 12.04 (Precise Pangolin)) ...

find ! -path "dir1" -iname "*.mp3"

cercherà i file MP3 nella cartella e nelle sottocartelle correnti tranne nella sottocartella dir1.

Uso:

find ! -path "dir1" ! -path "dir2" -iname "*.mp3"

... per escludere dir1 AND dir2


Non funziona per me. Né una delle risposte sopra. Cappello rosso.
Tharpa,

6

un buon trucco per evitare di stampare le directory potate è usare -print(funziona anche per -exec) dopo il lato destro del -ordopo -prune. Per esempio, ...

find . -path "*/.*" -prune -or -iname "*.j2"

stamperà il percorso di tutti i file sotto la directory corrente con l'estensione `.j2", saltando tutte le directory nascoste. Pulito. Ma stamperà anche la stampa del percorso completo di ciascuna directory che si sta saltando, come notato sopra. Tuttavia, il non segue, ...

find . -path "*/.*" -prune -or -iname "*.j2" -print

perché logicamente c'è un nascosto -anddopo l' -inameoperatore e prima della -print. Questo lo lega alla parte giusta della -orclausola a causa dell'ordine booleano di operazioni e associatività. Ma i documenti dicono che c'è un nascosto -printse non viene specificato (o uno dei suoi cugini ... -print0, ecc.). Quindi perché la parte sinistra della -orstampa non è? Apparentemente (e non l'ho capito dalla mia prima lettura della pagina man), questo è vero se non ce n'è uno con solo operatori descrittivi apparentemente non farebbe nulla, quindi immagino abbia senso com'è. Come accennato in precedenza, tutto funziona anche con , quindi quanto segue fornisce un elenco completo per ogni file con l'estensione desiderata, ma non elencando il primo livello di ogni directory nascosta, ...-print - o -execOVUNQUE, nel qual caso, l'impronta viene logicamente cosparsa in modo tale che tutto venga stampato. Se anche UNOprint operazione di stile espressa in alcuna clausola, tutti quelli logici nascosti scompaiono e ottieni solo ciò che specifichi. Ora, francamente, avrei potuto preferirlo viceversa, ma poi afind-execls -la

find . -path "*/.*" -prune -or -iname "*.j2" -exec ls -la -- {} +

Per me (e altri su questo thread), find sintassi diventa piuttosto barocca abbastanza rapidamente, quindi lancio sempre le parentesi per essere sicuro che so cosa si lega a ciò, quindi di solito creo una macro per l'abilità di tipo e forma tutte queste dichiarazioni come. ..

find . \( \( ... description of stuff to avoid ... \) -prune \) -or \
\( ... description of stuff I want to find ... [ -exec or -print] \)

È difficile sbagliare impostando il mondo in due parti in questo modo. Spero che questo aiuti, anche se sembra improbabile che qualcuno legga la 30esima risposta e la voti, ma si può sperare. :-)


5

È possibile utilizzare l'opzione prugna per raggiungere questo obiettivo. Come ad esempio:

find ./ -path ./beta/* -prune -o -iname example.com -print

Oppure l'opzione grep inversa grep -v:

find -iname example.com | grep -v beta

Puoi trovare istruzioni dettagliate ed esempi nel comando find di Linux per escludere le directory dalla ricerca .


La soluzione grep è l'unica che esclude tutte le directory con lo stesso nome. Quando si cerca di escludere "node_modules" questo è abbastanza utile.
bmacnaughton,

3
@bmacnaughton - non è vero! Sono venuto qui specificatamente cercando di escludere "node_modules" e dopo aver letto molte belle risposte ho deciso di find . -type f -print -o -path "*/node_modules" -prune... usando il carattere jolly questo "nodo_modules" salta a qualsiasi livello; l'uso -printsulla prima alternativa -type f -printfa stampare solo quella parte, quindi le directory "node_modules" non sono elencate. (può anche essere invertito: find . -path "*/node_modules" -prune -o -type f -print)
Stephen P

cosa sta facendo * / lì. Qual è il file esatto che vuoi escludere. Lo stai usando come jolly?
Siju V,

1
@StephenP, grazie per averlo sottolineato; Ho imparato la differenza tra l'utilizzo ./node_modulese */node_modulesda esso. Nel mio caso, dove node_modulesesiste solo nella directory in cui inizio la ricerca (e in quella node_modulesdirectory), posso usare find . -type f -print -o -path "./node_modules" -prune perché non ci sarà una node_modulesdirectory in nessun'altra directory.
bmacnaughton,

1
@SijuV - nella directory in cui stavo cercando c'era una node_modulessottodirectory, ma c'erano anche delle sottodirectory che avevano i loro node_modules ... usando ./node_modulescorrispondenze solo la sottodirectory nella directory node_modulescorrente .e la potava; usando si */node_modulesabbina e si elimina la directory a qualsiasi profondità, poiché *as come glob corrisponde a qualsiasi prefisso del percorso principale, ad esempio ./test5/main/node_modulesnon solo al ./prefisso. Il *è un jolly, ma come un glob non come un'espressione regolare.
Stephen P,

5
find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune

Non riesco a far funzionare questo. find ~/Projects -name '*.js' -\! -name 'node_modules' -prunesta ancora rigirando i file con il node_modulesloro percorso
mpen

1
@mpen, Da stackoverflow.com/questions/4210042/... , ho imparato che la sintassi che si desidera è find ~/Projects -path ~/Projects/node_modules -prune -o -name '*.js' -print. Il nome di quel percorso deve corrispondere esattamente a ciò che find verrebbe stampato se stesse stampando la directory.
PatS

4
find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'

sembra funzionare come

find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)

ed è più facile da ricordare IMO.


4

TLDR: comprendere le directory di root e personalizzare la ricerca da lì, utilizzando l' -path <excluded_path> -prune -oopzione. Non includere un finale/ alla fine del percorso escluso.

Esempio:

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print


Per utilizzare efficacemente findcredo che sia indispensabile avere una buona conoscenza della struttura della directory del file system. Sul mio computer di casa ho dischi rigidi multi-TB, con circa la metà del contenuto di cui è stato eseguito il backup utilizzando rsnapshot(ad es rsync.). Anche se il backup su un'unità fisicamente indipendente (duplicata), è montato nella /directory root ( ) del mio sistema /mnt/Backups/rsnapshot_backups/::

/mnt/Backups/
└── rsnapshot_backups/
    ├── hourly.0/
    ├── hourly.1/
    ├── ...
    ├── daily.0/
    ├── daily.1/
    ├── ...
    ├── weekly.0/
    ├── weekly.1/
    ├── ...
    ├── monthly.0/
    ├── monthly.1/
    └── ...

La /mnt/Backups/rsnapshot_backups/directory occupa attualmente ~ 2,9 TB, con ~ 60M file e cartelle; attraversare semplicemente quei contenuti richiede tempo:

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find /mnt/Backups/rsnapshot_backups | wc -l
60314138    ## 60.3M files, folders
34:07.30    ## 34 min

time du /mnt/Backups/rsnapshot_backups -d 0
3112240160  /mnt/Backups/rsnapshot_backups    ## 3.1 TB
33:51.88    ## 34 min

time rsnapshot du    ## << more accurate re: rsnapshot footprint
2.9T    /mnt/Backups/rsnapshot_backups/hourly.0/
4.1G    /mnt/Backups/rsnapshot_backups/hourly.1/
...
4.7G    /mnt/Backups/rsnapshot_backups/weekly.3/
2.9T    total    ## 2.9 TB, per sudo rsnapshot du (more accurate)
2:34:54          ## 2 hr 35 min

Pertanto, ogni volta che devo cercare un file sulla mia /partizione (root), devo occuparmi di (evitare se possibile) attraversando la mia partizione di backup.


ESEMPI

Tra gli approcci variamente suggeriti in questo thread ( Come escludere una directory nel comando find. ), Trovo che le ricerche usando la risposta accettata siano molto più veloci - con avvertimenti.

Soluzione 1

Diciamo che voglio trovare il file di sistema libname-server-2.a, ma non voglio cercare tra i miei rsnapshotbackup. Per trovare rapidamente un file di sistema, utilizzare il percorso exclude /mnt(ovvero, use /mnt, not /mnt/, oppure /mnt/Backups, o ...):

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
real    0m8.644s              ## 8.6 sec  <<< NOTE!
user    0m1.669s
 sys    0m2.466s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 3 sec     ## ~3 sec  <<< NOTE!

... trova quel file in pochi secondi, mentre questo richiede molto più tempo (sembra ricorrere a tutte le directory "escluse"):

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt/ -prune -o -name "*libname-server-2.a*" -print
find: warning: -path /mnt/ will not match anything because it ends with /.
/usr/lib/libname-server-2.a
real    33m10.658s            ## 33 min 11 sec (~231-663x slower!)
user    1m43.142s
 sys    2m22.666s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt/ -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 1775 sec    ## 29.6 min

Soluzione 2

Anche l'altra soluzione offerta in questo thread ( SO # 4210042 ) ha prestazioni scarse:

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -name "*libname-server-2.a*" -not -path "/mnt"
/usr/lib/libname-server-2.a
real    33m37.911s            ## 33 min 38 sec (~235x slower)
user    1m45.134s
 sys    2m31.846s

time find / -name "*libname-server-2.a*" -not -path "/mnt/*"
/usr/lib/libname-server-2.a
real    33m11.208s            ## 33 min 11 sec
user    1m22.185s
 sys    2m29.962s

SINTESI | CONCLUSIONI

Utilizzare l'approccio illustrato in " Soluzione 1 "

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print

vale a dire

... -path <excluded_path> -prune -o ...

notando che ogni volta che aggiungi il trailing /al percorso escluso, il findcomando quindi inserisce ricorsivamente (tutte quelle) /mnt/*directory - che nel mio caso, a causa delle /mnt/Backups/rsnapshot_backups/*sottodirectory, include anche ~ 2,9 TB di file da cercare! Non aggiungendo un finale/ la ricerca dovrebbe essere completata quasi immediatamente (in pochi secondi).

Anche la "Soluzione 2" ( ... -not -path <exclude path> ...) sembra cercare ricorsivamente tra le directory escluse - non restituendo le corrispondenze escluse, ma consumando inutilmente quel tempo di ricerca.


Ricerca all'interno di quei rsnapshotbackup:

Per trovare un file in uno dei miei rsnapshotbackup orari / giornalieri / settimanali / mensili ):

$ START="$(date +"%s")" && find 2>/dev/null /mnt/Backups/rsnapshot_backups/daily.0 -name '*04t8ugijrlkj.jpg'; END="$(date +"%s")"; TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/mnt/Backups/rsnapshot_backups/daily.0/snapshot_root/mnt/Vancouver/temp/04t8ugijrlkj.jpg
find command took 312 sec   ## 5.2 minutes: despite apparent rsnapshot size
                            ## (~4 GB), it is in fact searching through ~2.9 TB)

Escludendo una directory nidificata:

Qui, voglio escludere una directory nidificata, ad esempio /mnt/Vancouver/projects/ie/claws/data/*durante la ricerca da /mnt/Vancouver/projects/:

$ time find . -iname '*test_file*'
./ie/claws/data/test_file
./ie/claws/test_file
0:01.97

$ time find . -path '*/data' -prune -o -iname '*test_file*' -print
./ie/claws/test_file
0:00.07

A parte: l' aggiunta -printalla fine del comando elimina la stampa della directory esclusa:

$ find / -path /mnt -prune -o -name "*libname-server-2.a*"
/mnt
/usr/lib/libname-server-2.a

$ find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a

Non è la dimensione dei file che rallenta find, è il numero di voci della directory che deve esaminare. Quindi è molto peggio se hai molti, molti piccoli file (specialmente se sono tutti moltiplicati!) Che se hai solo una manciata di file multi-gigabyte.
Toby Speight,

@TobySpeight: buon punto. Ho citato le dimensioni dello spazio di ricerca per indicare la scala, che contiene anche molti file. Una rapida ricerca di root (/) con sudo ls -R / | wc -lindica ~ 76,5 milioni di file (molti dei quali sono sottoposti a backup tranne i file di sistema "non config"); /mnt/Vancouver/con ls -R | wc -lindica ~ 2.35 M file; /home/victoria/contiene 0,668 milioni di file.
Victoria Stuart,

4

Puoi anche usare espressioni regolari per includere / escludere alcuni file / dirs la tua ricerca usando qualcosa del genere:

find . -regextype posix-egrep -regex ".*\.(js|vue|s?css|php|html|json)$" -and -not -regex ".*/(node_modules|vendor)/.*" 

Questo ti darà solo tutti i file js, vue, css, ecc. Ma esclude tutti i file nelle cartelle node_modulese vendor.


3

Stavo usando findper fornire un elenco di file xgettexte volevo omettere una directory specifica e il suo contenuto. Ho provato molte permutazioni di -pathcombinato con -prunema non sono stato in grado di escludere completamente la directory che volevo andare.

Anche se sono stato in grado di ignorare il contenuto della directory che volevo ignorare, findquindi ho restituito la directory stessa come uno dei risultati, che ha causatoxgettext arresto anomalo di conseguenza (non accetta directory; solo file).

La mia soluzione era semplicemente usare grep -vper saltare la directory che non volevo nei risultati:

find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext

Se c'è o meno un argomento findche funzionerà al 100%, non posso dire con certezza. L'utilizzo è grepstato una soluzione rapida e semplice dopo alcuni mal di testa.


3

Nessuna delle risposte precedenti va bene su Ubuntu. Prova questo:

find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"

L'ho trovato qui


Non vedo alcun motivo per cui una delle risposte con più di 100 punti non dovrebbe funzionare su Ubuntu.
Axel Beckert,

mmm vediamo? forse perché li ho provati tutti?
sixro,

find è ovunque la stessa implementazione su tutte le distribuzioni Linux - quella del Progetto GNU. L'unica differenza potrebbe essere le versioni. Ma i cambiamenti nell'ultimo decennio non sono stati così invasivi, tranne forse per la corrispondenza dei permessi.
Axel Beckert,

3

Questo è adatto per me su un Mac:

find . -name *.php -or -path "./vendor" -prune -or -path "./app/cache" -prune

Escluderà vendore app/cachedir per il nome della ricerca con il suffisso php.


Meglio mettere virgolette singole attorno a '* .php' o non troverai quello che stai cercando.
Br.

3

Per quelli di voi su versioni precedenti di UNIX che non possono utilizzare -path o -non

Testato su SunOS 5.10 bash 3.2 e SunOS 5.11 bash 4.4

find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f

Potrebbe passare più della directory specificata.
MUY Belgio,

2

how-to-use-prune-option-of-find-in-sh è un'ottima risposta di Laurence Gonsalves su come -prunefunziona.

Ed ecco la soluzione generica:

find /path/to/search                    \
  -type d                               \
    \( -path /path/to/search/exclude_me \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print

Per evitare di digitare /path/to/seach/più volte, avvolgi findin una pushd .. popdcoppia.

pushd /path/to/search;                  \
find .                                  \
  -type d                               \
    \( -path ./exclude_me               \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print;         \
 popd

1
Da stackoverflow.com/questions/4210042/… , ho appreso che la sintassi utilizzata per il -pathdeve corrispondere al nome che troverà se dovesse stampare la directory in modo tale, ad esempio find . -path ./.git -prune -o -print, oppure find $HOME/foo -path $HOME/foo/.git -prune -o -print Alcune delle risposte dicono semplicemente -path somedirche purtroppo è non abbastanza preciso per essere utile.
PatS

2

Per quello che mi serviva ha funzionato così, trovando landscape.jpgin tutti i server partendo da root ed escludendo la ricerca nella /vardirectory:

find / -maxdepth 1 -type d | grep -v /var | xargs -I '{}' find '{}' -name landscape.jpg

find / -maxdepth 1 -type delenca tutti d irectories in/

grep -v /var esclude `/ var 'dall'elenco

xargs -I '{}' find '{}' -name landscape.jpgeseguire qualsiasi comando, come findcon ogni directory / risultato dalla lista


Aspetta un secondo, /non è ancora escluso. Potrebbe essere necessario sed 1d.
Simba

2

I seguenti comandi funzionano:

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

In caso di problemi con find, utilizzare l' -D treeopzione per visualizzare le informazioni sull'analisi dell'espressione.

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

O il -D all, per vedere tutte le informazioni sull'esecuzione.

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

1

Ho trovato il nome delle funzioni nei file sorgenti C escludere * .o ed escludere * .swp ed escludere (non file normale) ed escludere l'output di dir con questo comando:

find .  \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach

1

Meglio usare l' execazione che il forciclo:

find . -path "./dirtoexclude" -prune \
    -o -exec java -jar config/yuicompressor-2.4.2.jar --type js '{}' -o '{}' \;

La exec ... '{}' ... '{}' \;verrà eseguita una volta per ogni file corrispondente, sostituendo le parentesi '{}'con il nome del file corrente.

Si noti che le parentesi graffe sono racchiuse tra virgolette singole per proteggerle dall'interpretazione come punteggiatura di script di shell * .


Appunti

* Dalla sezione ESEMPI della find (GNU findutils) 4.4.2pagina man


1
Domanda molto vecchia, ma con ancora margini di miglioramento. L'ho trovato per caso cercando di risolvere un problema simile e nessuna delle risposte è stata soddisfacente.
Alberto,

Uso execspesso l' azione e la trovo molto utile. In genere aggiungo virgolette tra {}nel caso in cui ci siano spazi nei percorsi dei file che dà "{}".
Ludovic Kuty il

@lkuty Stavo per modificare il mio post per riflettere il tuo commento, ma dopo un rapido test (senza virgolette, {}funziona per file con spazi bianchi nei loro nomi) e uno sguardo alle pagine man, sembra che la citazione sia necessaria solo per evitare per essere interpretati erroneamente come punteggiatura di script shell. In questo caso, utilizzeresti una citazione singola:'{}'
Alberto

Penso che dovevo usarlo per creare cpo mvo rm. Lo controllerò
Ludovic Kuty il

1

Ho provato il comando sopra, ma nessuno di quelli che usano "-prune" funziona per me. Alla fine l'ho provato con il comando seguente:

find . \( -name "*" \) -prune -a ! -name "directory"
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.