Voglio eliminare ricorsivamente tutti i file a cui non si accede da un po' di tempo nella cartella a
, ad eccezione di tutti i file nella sottocartella b
.
find a ( -name b -prune ) -o -type f -delete
Tuttavia, ricevo un messaggio di errore:
trova:l'azione -delete attiva automaticamente -depth, ma -prune non esegue
nulla quando -depth è attivo. Se vuoi continuare comunque,
usa esplicitamente l'opzione -depth.
Aggiunta di -depth
causa tutti i file in b
da includere, che deve non succedere.
Qualcuno conosce un modo sicuro per farlo funzionare?
Risposta accettata:
un modo è usare -exec rm
invece di -delete
.
find a ( -name b -prune ) -o -type f -exec rm {} +
in alternativa usa -not -path
invece di -prune
:
find a -not -path "*/b*" -type f -delete
Spiegazione del perché -prune
collide con -delete
:
trova lamentele quando provi a usare -delete
con -prune
perché -delete
implica -depth
e -depth
rende -prune
inefficace.
osserva il comportamento di trova con e senza -depth
:
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
Non vi è alcuna garanzia sull'ordine in una singola directory. Ma c'è una garanzia che una directory venga elaborata prima del suo contenuto. Nota foo/
prima di qualsiasi foo/*
e foo/bar
prima di qualsiasi foo/bar/*
.
Questo può essere annullato con -depth
.
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
Nota che ora tutti i foo/*
appaiono prima di foo/
. Lo stesso con foo/bar
.
maggiori spiegazioni:
-prune
impedisce a find di scendere in una directory. In altre parole-prune
salta il contenuto della directory. Nel tuo caso-name b -prune
significa che quando trova raggiunge una directory con il nomeb
salterà la directory comprese tutte le sottodirectory.-depth
fa find per elaborare il contenuto di una directory prima della directory stessa. Ciò significa che nel momento in cui find elabora la voce di directoryb
il suo contenuto è già stato elaborato. Quindi-prune
è inefficace con-depth
in vigore.-delete
implica-depth
quindi può eliminare prima il contenuto e poi la directory vuota.-delete
rifiuta di eliminare le directory non vuote.
Spiegazione del metodo alternativo:
find a -not -path "*/b*" -type f -delete
Questo potrebbe essere più facile da ricordare o meno.
Questo comando scende ancora nella directory b
ed elabora ogni singolo file in esso contenuto solo per -not
di respingerli. Questo può essere un problema di prestazioni se la directory b
è enorme.
-path
funziona in modo diverso da -name
. -name
corrisponde solo al nome (del file o della directory) mentre -path
corrisponde all'intero percorso. Ad esempio, osserva il percorso /home/lesmana/foo/bar
. -name bar
corrisponderà perché il nome è bar
. -path "*/foo*"
corrisponderà perché la stringa /foo
è nel percorso. -path
ha alcune complessità che dovresti capire prima di usarlo. Leggi la pagina man di find
per maggiori dettagli.
Attenzione che questo non è infallibile al 100%. Ci sono possibilità di "falsi positivi". Il modo in cui il comando è scritto sopra salterà qualsiasi file che ha una directory padre il cui nome inizia con b
(positivo). Ma salterà anche qualsiasi file il cui nome inizia con b
indipendentemente dalla posizione nell'albero (falso positivo). Questo può essere risolto scrivendo un'espressione migliore di "*/b*"
. Questo è lasciato come esercizio per il lettore.
Presumo che tu abbia usato a
e b
poiché i segnaposto e i nomi reali sono più simili a allosaurus
e brachiosaurus
. Se metti brachiosaurus
al posto di b
quindi la quantità di falsi positivi sarà drasticamente ridotta.
Almeno i falsi positivi saranno non cancellato, quindi non sarà così tragico. Inoltre, puoi verificare la presenza di falsi positivi eseguendo prima il comando senza -delete
(ma ricorda di inserire la -depth
implicita ) ed esaminare l'output.
find a -not -path "*/b*" -type f -depth