Come utilizzare l'opzione '-prune' di 'find' in sh?
Domanda
Non capisco del tutto l'esempio fornito da man find
, qualcuno può darmi qualche esempio e spiegazione?Posso combinare l'espressione regolare in esso?
La domanda più dettagliata è questa:
Scrivi uno script di shell, changeall
, che ha un'interfaccia simile changeall [-r|-R] "string1" "string2"
.Troverà tutti i file con il suffisso .h
, .C
, .cc
, O .cpp
e modificare tutte le occorrenze di string1
A string2
. -r
è un'opzione per rimanere solo nella directory corrente o includere le sottodir.
NOTA:
- Per il caso non ricorsivo,
ls
NON è consentito, potremmo solo usarefind
Esed
. - ho provato
find -depth
ma NON era supportato.Ecco perché mi chiedevo se-prune
potrebbe aiutare, ma non ho capito l'esempioman find
.
EDIT2:Stavo svolgendo un compito, non ho posto domande nei dettagli perché vorrei finirlo da solo.Dato che l'ho già fatto e consegnato, ora posso formulare l'intera domanda.Inoltre, sono riuscito a completare il compito senza utilizzarlo -prune
, ma vorrei impararlo comunque.
Soluzione
La cosa su cui avevo trovato confuso -prune
è che è un'azione (come -print
), non un test (come -name
).Altera l'elenco delle "cose da fare", ma restituisce sempre vero.
Il modello generale per l'utilizzo -prune
è questo:
find [path] [conditions to prune] -prune -o \
[your usual conditions] [actions to perform]
Praticamente lo vuoi sempre -o
(OR logico) immediatamente dopo -prune
, perché quella prima parte del test (fino a incluso -prune
) sarà di ritorno falso per le cose che realmente desideri (ad esempio:le cose che tu non voglio eliminare).
Ecco un esempio:
find . -name .snapshot -prune -o -name '*.foo' -print
Questo troverà i file "*.foo" che non si trovano nelle directory ".snapshot".In questo esempio, -name .snapshot
costituisce il [conditions to prune]
, E -name '*.foo' -print
È [your usual conditions]
E [actions to perform]
.
Note importanti:
Se tutto ciò che vuoi fare è stampare i risultati potresti essere abituato a tralasciare il file
-print
azione.Tu in genere non vuoi farlo quando lo usi-prune
.Il comportamento predefinito di find è "e" the intero espressione con il
-print
azione se non ci sono azioni diverse da-prune
(ironicamente) alla fine.Ciò significa che scrivendo questo:find . -name .snapshot -prune -o -name '*.foo' # DON'T DO THIS
equivale a scrivere questo:
find . \( -name .snapshot -prune -o -name '*.foo' \) -print # DON'T DO THIS
il che significa che stamperà anche il nome della directory che stai eliminando, che di solito non è quello che desideri.E' invece meglio specificare esplicitamente il
-print
azione se è quello che vuoi:find . -name .snapshot -prune -o -name '*.foo' -print # DO THIS
Se la tua "condizione abituale" corrisponde a file che corrispondono anche alla tua condizione di prune, quei file lo faranno non essere incluso nell'output.Il modo per risolvere questo problema è aggiungere a
-type d
dipendente dalle condizioni della tua prugna.Ad esempio, supponiamo di voler eliminare qualsiasi directory che inizia con
.git
(questo è certamente un po' artificioso: normalmente è sufficiente rimuovere solo la cosa denominata esattamente.git
), ma a parte questo volevo vedere tutti i file, inclusi i file come.gitignore
.Potresti provare questo:find . -name '.git*' -prune -o -type f -print # DON'T DO THIS
Questo sarebbe non includere
.gitignore
nell'uscita.Ecco la versione fissa:find . -type d -name '.git*' -prune -o -type f -print # DO THIS
Suggerimento extra:se stai utilizzando la versione GNU di find
, la pagina texinfo per find
ha una spiegazione più dettagliata della sua manpage (come è vero per la maggior parte delle utility GNU).
Altri suggerimenti
Attenzione che -prune non impedisce scendere in qualsiasi directory come alcuni hanno detto. Previene scendendo nelle directory che corrispondono il test è applicato a. Forse alcuni esempi aiuteranno (vedere il fondo per un esempio di espressione regolare). Ci scusiamo per questo essere così lungo.
$ 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
Normalmente il modo nativo che fare le cose in Linux e il nostro modo di pensare è da sinistra a destra.
Quindi, si dovrebbe andare e scrivere quello che stai cercando per il primo:
find / -name "*.php"
allora probabilmente ha colpito entrare e rendersi conto che si stanno ottenendo troppi file da
directory non si desidera.
Diamo escludere / media per evitare la ricerca le unità montate.
Si dovrebbe ora solo aggiungere il seguente al comando precedente:
-print -o -path '/media' -prune
in modo che il comando finale è:
find / -name "*.php" -print -o -path '/media' -prune
............... | <--- Includere ---> | .................... | <---------- --------- escludere> |
Credo che questa struttura è molto più facile e correlato al giusto approccio
In aggiunta al consiglio dato in altre risposte (non ho rep per creare risposte) ...
Quando si combina -prune
con altre espressioni, c'è una sottile differenza nel comportamento a seconda di quale altre espressioni vengono utilizzati.
@Laurence Gonsalves' si trova il "* .foo" i file che non sono sotto ".snapshot" directory: -
find . -name .snapshot -prune -o -name '*.foo' -print
Tuttavia, questo leggermente diverso a breve mano sarà, forse inavvertitamente, elencare anche la directory .snapshot
(e le directory .snapshot nidificate): -
find . -name .snapshot -prune -o -name '*.foo'
Il motivo è (secondo la pagina di manuale sul mio sistema): -
Se l'espressione data non contiene alcuna delle primarie -exec, -ls, -ok o -print, l'espressione data è efficacemente sostituito da:
(given_expression) -print
Cioè, il secondo esempio è l'equivalente di entrare nel seguito, così da modificare il raggruppamento dei termini: -
find . \( -name .snapshot -prune -o -name '*.foo' \) -print
Questa è almeno stato visto su Solaris 5.10. Avendo usato vari sapori di * nix per circa 10 anni, ho solo recentemente cercato un motivo per cui questo accade.
Prune è un non FattorialeMenoUno cambiato in ogni directory.
Dalla pagina man
Se -depth non è dato, vero; se il file è una directory, non scende in esso. Se viene dato -depth, false; nessun effetto.
In sostanza non sarà desend in qualsiasi sottodirectory.
Prendete questo esempio:
Sono disponibili le seguenti directory
- / home / test2
- / home / test2 / test2
Se si esegue find -name test2
:
Si tornerà entrambe le directory
Se si esegue find -name test2 -prune
:
Si tornerà solo / home / test2 in quanto non scenderà in / home / test2 per trovare / home / test2 / test2
Non sono un esperto in questo (e questa pagina è stato molto disponibile con http://mywiki.wooledge.org / UsingFind )
-path
Appena notato è per un percorso che corrisponde pienamente la stringa / percorso che viene subito dopo find
(.
in tesi esempi) dove, come -name
corrisponde a tutti BaseNames.
find . -path ./.git -prune -o -name file -print
blocca la directory .git nella directory corrente ( come risultato in .
)
find . -name .git -prune -o -name file -print
blocca tutte le sottodirectory .git ricorsivamente.
Si noti la ./
è estremamente importante !! -path
deve corrispondere a un percorso ancorata al .
o ciò che viene subito dopo trovare se si ottiene incontri fuori di esso (dall'altra parte del o '-o
') probabilmente non essere potati!
Io ero ingenuamente a conoscenza di questo e mi ha messo di utilizzare path quando è grande quando non si vuole potare tutte sottodirectory con lo stesso nome di base: D
Mostra tutto, compreso dir se stesso, ma non i suoi lunghi contenuti noiose:
find . -print -name dir -prune
Se avete letto tutte le buone risposte qui la mia comprensione è che ora il seguente restituiscono tutte lo stesso risultato:
find . -path ./dir1\* -prune -o -print
find . -path ./dir1 -prune -o -print
find . -path ./dir1\* -o -print
#look no prune at all!
Ma l'ultimo avrà molto più a lungo in quanto cerca ancora fuori tutto in dir1. Credo che la vera questione è come -or
fuori risultati indesiderati senza peraltro riuscire a cercare.
Quindi credo che i mezzi prugna fanno partite passate non decenti ma contrassegnarla come eseguita ...
http://www.gnu.org/software/findutils/ manuale / html_mono / find.html "Questo però non è per effetto dell'azione '-prune' (che impedisce solo ulteriore discesa, non fa che noi ignoriamo che articolo). Invece, questo effetto è dovuto all'uso di '-o'. Dal momento che il lato sinistro della “o” condizione è riuscita per ./src/emacs, non è necessario valutare il diritto-mano-lato ( '-print') a tutti per questo particolare file ".
find
crea un elenco di file. Si applica il predicato che hai fornito a ciascuno e restituisce quelli che passano.
Questa idea che -prune
mezzi escludere dai risultati era davvero fonte di confusione per me. È possibile escludere un file senza prugna:
find -name 'bad_guy' -o -name 'good_guy' -print // good_guy
Tutti -prune
fa è modificare il comportamento della ricerca. Se la partita in corso è una directory, si dice "hey find
, che file appena abbinato, Non scendere in esso" . Rimuove solo quell'albero (ma non il file stesso) dalla lista dei file per la ricerca.
Si deve essere denominato -dont-descend
.